[
  {
    "path": ".gitignore",
    "content": "# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Libraries\n*.lib\n*.a\n*.la\n*.lo\n\n# Shared objects (inc. Windows DLLs)\n*.so\n*.so.*\n\n# Executables\n*.out\n*.hex\ngps-sim\n\n# Debug files\n*.dSYM/\n\n# Output\n*.bin\n\n# Netbeans project folder\nnbproject/*\n\n# Rinex files\n*.gz\n\n# Almanac files\n*.sem\n*.sem.txt\n*.yuma\n*.alm\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2021 Mictronics\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "Makefile",
    "content": "HACKRFSDR ?= no\nPLUTOSDR ?= no\n\nDIALECT = -std=c11\nCFLAGS += $(DIALECT) -Og -g -W -Wall -D_GNU_SOURCE\nLIBS = -lm -pthread -lpthread -lcurl -lz -lpanel -lncurses\nLDFLAGS =\nSDR_OBJ = sdr_iqfile.o\n\nifeq ($(HACKRFSDR), yes)\n    SDR_OBJ += sdr_hackrf.o\n    CPPFLAGS += -DENABLE_HACKRFSDR\n    CFLAGS += $(shell pkg-config --cflags libhackrf)\n    LIBS_SDR += $(shell pkg-config --libs libhackrf)\nendif\n\nifeq ($(PLUTOSDR), yes)\n    SDR_OBJ += sdr_pluto.o\n    CPPFLAGS += -DENABLE_PLUTOSDR\n    CFLAGS += $(shell pkg-config --cflags libiio libad9361)\n    LIBS_SDR += $(shell pkg-config --libs libiio libad9361)\nendif\n\nall: gps-sim\n\t\n%.o: %.c *.h\n\t$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@\n\ngps-sim: fifo.o almanac.o gps.o gui.o sdr.o gps-sim.o $(SDR_OBJ) $(COMPAT)\n\t$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_SDR)\n\nclean:\n\trm -f *.o  gps-sim\n"
  },
  {
    "path": "README.md",
    "content": "# multi-sdr-gps-sim\n\nmulti-sdr-gps-sim generates a GPS L1 baseband signal IQ data stream, which is then transmitted by a\nsoftware-defined radio (SDR) platform. Supported at the moment are HackRF, ADLAM-Pluto and binary IQ file output.\nThe software interacts with the user through a curses based text user interface (TUI) in terminal.\n\nProject based on work of [Takuji Ebinuma](https://github.com/osqzss/) and [IvanKor](https://github.com/IvanKor).\n\n### Generating the GPS signal\n\nThe user is able to assign a static location directly through the command line or sends motion data through a predefined input file.\nIn addition the simulated position can be modified in realtime by user inputs.\n\nThe user also specifies the GPS satellite constellation through a GPS broadcast ephemeris file. The daily GPS broadcast ephemeris file\nis a merge of the individual site navigation files into one.\n\nThese files are then used to generate the simulated pseudorange and Doppler for the GPS satellites in view. This simulated range data is\nthen used to generate the digitized I/Q samples for the GPS signal which are then feed into ADALM-Pluto SDR to transmit the GPS L1 frequency.\n\nThe simulation start time can be specified if the corresponding set of ephemerides is available. Otherwise the first time of ephemeris in the RINEX navigation file\nis selected. RINEX input format 2 and 3 are supported.\n\n__Note__\n\nThe SDR internal oscillator must be precise enough (frequency offset) and stable (temperature drift) for GPS signal generation.\nIdeally the SDR shall be clocked from either by TCXO or more expensive (but highest precision) OCXO.\n\nBest experience with HackRF.\n\n### Build instructions\n\n#### Dependencies\n\nBuild depends on libm, libpthread, libcurl4-openssl-dev, libncurses, libz and libhackrf.\n\nYou will also need the latest build and install of libhackrf, libad9361-dev and libiio-dev. The Debian packages\nlibad9361-dev that is available up to Debian 9 (stretch) is outdated and missing a required function.\n\nSo you have to build packages from source:\n\nThe first step is to fetch the dependencies, which as of now is only libxml2. On a Debian-flavoured GNU/Linux distribution, like Ubuntu for instance:\n\n```\n$ sudo apt-get install libxml2 libxml2-dev bison flex libcdk5-dev cmake\n```\n\nDepending on the backend (how you want to attach the IIO device), you may need at least one of:\n\n```\n$ sudo apt-get install libaio-dev libusb-1.0-0-dev libserialport-dev libxml2-dev libavahi-client-dev doxygen graphviz\n```\n\nThen build in this order:\n\n```\n$ git clone https://github.com/analogdevicesinc/libiio.git\n$ cd libiio\n$ cmake ./\n$ make\n$ sudo make install\n```\n\n```\n$ git clone https://github.com/analogdevicesinc/libad9361-iio.git\n$ cd libad9361-iio\n$ cmake ./\n$ make\n$ sudo make install\n```\n\n#### Building under Linux with GCC\n\n```\n$ git clone https://github.com/mictronics/multi-sdr-gps-sim\n$ cd multi-sdr-gps-sim\n```\n\nWith HackRF support: `make all HACKRFSDR=yes` (depends on libhackrf)\n\nWith ADLAM-PLUTO support: `make all PLUTOSDR=yes` (depends on libiio and libad9361-iio)\n\nFull SDR support: `make all HACKRFSDR=yes PLUTOSDR=yes`\n\n### Usage\n\n````\ngps-sim [options]\nOptions:\n--nav-file          -e  <filename> RINEX navigation file for GPS ephemeris (required)\n--geo-loc           -l  <location> Latitude, Longitude, Height (static mode) e.g. 35.681298,139.766247,10.0\n--start             -s  <date,time> Scenario start time YYYY/MM/DD,hh:mm:ss (use 'now' for actual time)\n--gain              -g  <gain> Set TX gain, HackRF: 0-47dB, Pluto: -80-0dB (default 0)\n--duration          -d  <seconds> Duration in seconds\n--target            -t  <distance,bearing,height> Target distance [m], bearing [°] and height [m]\n--ppb               -p  <ppb> Set oscillator error in ppb (default 0)\n--radio             -r  <name> Set the SDR device type name (default none)\n--uri               -U  <uri> ADLAM-Pluto URI\n--network           -N  <network> ADLAM-Pluto network IP or hostname (default pluto.local)\n--motion            -m  <name> User motion file (dynamic mode)\n--iq16                  Set IQ sample size to 16 bit (default 8 bit)\n--disable-iono      -I  Disable ionospheric delay for spacecraft scenario\n--verbose           -v  Show verbose output and details about simulated channels\n--interactive       -i  Use interactive mode\n--amplifier         -a  Enable TX amplifier (default OFF)\n--use-ftp           -f  Pull actual RINEX navigation file from FTP server\n--rinex3            -3  Use RINEX v3 navigation data format\n--disable-almanac       Disable transmission of almanac information\n--help              -?  Give this help list\n--usage                 Give a short usage message\n--version           -V  Print program version\n\nSDR device types (use with --radio or -r option):\n    none\n    iqfile\n    hackrf\n    plutosdr\n````\n\n### License\n\nCopyright &copy; 2021 Mictronics\nDistributed under the [MIT License](http://www.opensource.org/licenses/mit-license.php).\n"
  },
  {
    "path": "almanac.c",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n#include \"gps-sim.h\"\n#include \"almanac.h\"\n\nstatic almanac_gps_t almanac_gps;\n\nstruct sem_file {\n    const char *filename;\n    FILE *stream;\n};\n\n/**\n * Initialize empty almanac.\n */\nalmanac_gps_t* almanac_init(void) {\n    almanac_gps.valid = 0;\n    almanac_prn_t* a = NULL;\n    for (int prn = 0; prn < MAX_SAT; prn++) {\n        a = &almanac_gps.sv[prn];\n        a->ura = 0;\n        a->health = 0;\n        a->config_code = 0;\n        a->svid = 0;\n        a->svn = 0;\n        a->valid = 0;\n        a->toa.sec = 0.0;\n        a->toa.week = 0;\n        a->e = 0.0;\n        a->delta_i = 0.0;\n        a->omegadot = 0.0;\n        a->sqrta = 0.0;\n        a->omega0 = 0.0;\n        a->aop = 0.0;\n        a->m0 = 0.0;\n        a->af0 = 0.0;\n        a->af1 = 0.0;\n    }\n    return &almanac_gps;\n}\n\n/**\n * Curl file writer callback.\n */\nstatic size_t fwrite_sem(void *buffer, size_t size, size_t nmemb, void *stream) {\n    struct sem_file *out = (struct sem_file *) stream;\n    if (out && !out->stream) {\n        /* open file for writing */\n        out->stream = fopen(out->filename, \"wb\");\n        if (!out->stream)\n            return -1; /* failure, can't open file to write */\n    }\n    return fwrite(buffer, size, nmemb, out->stream);\n}\n\n/**\n * Read almanac from local file.\n * sem format expected.\n */\nCURLcode almanac_read_file(void) {\n    char buf[100];\n    char title[24];\n    char *pbuf;\n    unsigned int n, week, sec, id;\n    FILE *fp = fopen(\"almanac.sem\", \"rt\");\n    almanac_prn_t* a = NULL;\n\n    // Start with empty almanac\n    almanac_init();\n\n    if (!fp) {\n        return CURLE_READ_ERROR;\n    }\n\n    pbuf = fgets(buf, sizeof (buf), fp);\n    if (pbuf == NULL || sscanf(buf, \"%u %24s\", &n, title) != 2) goto error;\n\n    pbuf = fgets(buf, sizeof (buf), fp);\n    if (pbuf == NULL || sscanf(buf, \"%u %u\", &week, &sec) != 2) goto error;\n\n    n -= 1; // PRN in file counts 1-32, array counts 0-31\n    if (n > 31) n = 31; // Max 32 PRN's to read (0-31)\n\n    for (unsigned int j = 0; j <= n; j++) {\n        pbuf = fgets(buf, sizeof (buf), fp);\n        if (pbuf == NULL) goto error;\n        // Check and skip blank line\n        if (buf[0] == '\\n' || buf[0] == '\\r') {\n            pbuf = fgets(buf, sizeof (buf), fp);\n            if (pbuf == NULL) goto error;\n        }\n\n        if (sscanf(buf, \"%u\", &id) != 1) goto error;\n        if (id == 0) id = 1;\n        if (id > 32) id = 32;\n\n        a = &almanac_gps.sv[id - 1];\n\n        a->svid = (unsigned short) id;\n\n        // SVN is optional, could be a blank line\n        pbuf = fgets(buf, sizeof (buf), fp);\n        if (pbuf == NULL) goto error;\n        if (buf[0] == '\\n' || buf[0] == '\\r') {\n            a->svn = 0;\n        } else {\n            if (sscanf(buf, \"%hu\", &a->svn) != 1) goto error;\n        }\n\n        pbuf = fgets(buf, sizeof (buf), fp);\n        if (pbuf == NULL) goto error;\n        if (sscanf(buf, \"%hhu\", &a->ura) != 1) goto error;\n        if (a->ura > 15) a->ura = 15;\n\n        pbuf = fgets(buf, sizeof (buf), fp);\n        if (pbuf == NULL) goto error;\n        if (sscanf(buf, \"%lf %lf %lf\", &a->e, &a->delta_i, &a->omegadot) != 3) goto error;\n\n        pbuf = fgets(buf, sizeof (buf), fp);\n        if (pbuf == NULL) goto error;\n        if (sscanf(buf, \"%lf %lf %lf\", &a->sqrta, &a->omega0, &a->aop) != 3) goto error;\n\n        pbuf = fgets(buf, sizeof (buf), fp);\n        if (pbuf == NULL) goto error;\n        if (sscanf(buf, \"%lf %lf %lf\", &a->m0, &a->af0, &a->af1) != 3) goto error;\n\n        pbuf = fgets(buf, sizeof (buf), fp);\n        if (pbuf == NULL) goto error;\n        if (sscanf(buf, \"%hhu\", &a->health) != 1) goto error;\n        if (a->health > 63) a->health = 63;\n\n        pbuf = fgets(buf, sizeof (buf), fp);\n        if (pbuf == NULL) goto error;\n        if (sscanf(buf, \"%hhu\", &a->config_code) != 1) goto error;\n        if (a->config_code > 15) a->config_code = 15;\n\n        /**\n         * ublox u-center software provides the full GPS week number whereas Celestrak follows\n         * IC-GPS-200L, p. 116, 20.3.3.5.1.5 Almanac Reference Week:\n         * The WNa term consists of eight bits which shall be a modulo 256 binary\n         * representation of the GPS week number...\n         * Celestrak almanac files use a modulo 256 week number in file name.\n         * See https://celestrak.com/GPS/almanac/SEM/2021/\n\t *\n\t * NOTE: It seems like sometime in the last four years this changed.\n\t * a->toa.week = (int) week % 256; results in incorrect date parsing.\n         */\n        a->toa.week = (int) week;\n        a->toa.sec = (double) sec;\n        // GPS week rollover\n        a->toa.week += 2048;\n        a->valid = 1;\n        almanac_gps.valid = 1; // We have at least one valid record\n    }\n    fclose(fp);\n    return CURLE_OK;\n\nerror:\n    if (!feof(fp)) {\n        // Not end of file, something wrong\n        // Drop all parsed almanac data on error\n        almanac_init();\n    }\n    /**\n     * If this is the end of file we may read less records than what \n     * field \"number of records\" announced.\n     * Found this happening when saving almanac.sem in ublox u-center software.\n     */\n    fclose(fp);\n    return CURLE_READ_ERROR;\n}\n\n/**\n * Read almanac from online source.\n * sem format expected.\n *  \n */\nCURLcode almanac_download(void) {\n    CURL *curl;\n    CURLcode res = CURLE_GOT_NOTHING;\n    struct sem_file sem = {\n        \"almanac.sem\",\n        NULL\n    };\n\n    curl_global_init(CURL_GLOBAL_DEFAULT);\n    curl = curl_easy_init();\n    if (curl) {\n        curl_easy_setopt(curl, CURLOPT_URL, ALMANAC_DOWNLOAD_SEM_URL);\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_sem);\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &sem);\n        curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);\n        res = curl_easy_perform(curl);\n        curl_easy_cleanup(curl);\n    }\n\n    if (sem.stream)\n        fclose(sem.stream);\n\n    curl_global_cleanup();\n\n    if (res != CURLE_OK) {\n        return res;\n    }\n\n    return (almanac_read_file());\n}\n"
  },
  {
    "path": "almanac.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#ifndef ALMANAC_H\n#define ALMANAC_H\n\n#include <curl/curl.h>\n#include \"gps.h\"\n\n#define ALMANAC_DOWNLOAD_SEM_URL \"https://www.celestrak.com/GPS/almanac/SEM/almanac.sem.txt\"\n\ntypedef struct {\n    unsigned char ura; // User Range Accuracy lookup code, [0-15], see p. 91 IS-GPS-200L, 0 <2.4m, 15 is >6144m\n    unsigned char health; // 0=healthy, unhealthy otherwise [], subframe 4 and 5, page 25 six-bit health code\n    unsigned char config_code; // configuration code [], if >=9 Anti-Spoofing is on\n    unsigned short svid; // GPS SV id or prn number 1-32 []  \n    unsigned short svn; // Satellite vehicle number []\n    unsigned int valid; // Validity of this almanac\n    double e; // eccentricity []\n    double delta_i; // orbital inclination at reference time [rad]\n    double omegadot; // rate of right ascension [rad/s]\n    double sqrta; // square root of the semi-major axis [m^(1/2)]\n    double omega0; // longitude of ascending node of orbit plane at weekly epoch [rad]\n    double aop; // argument of perigee [rad]\n    double m0; // mean anomaly at reference time [rad]\n    double af0; // polynomial clock correction coefficient (clock bias) [s], Note: parameters from ephemeris preferred vs almanac (22 vs 11 bits)\n    double af1; // polynomial clock correction coefficient (clock drift) [s/s], Note: parameters from ephemeris preferred vs almanac (16 vs 11 bits)\n    gpstime_t toa; // almanac time of applicability (reference time) [s]\n} almanac_prn_t;\n\ntypedef struct {\n    unsigned int valid; // Almanac validity\n    almanac_prn_t sv[MAX_SAT]; // 32 SV's almanac\n} almanac_gps_t;\n\nalmanac_gps_t* almanac_init(void);\nCURLcode almanac_read_file(void);\nCURLcode almanac_download(void);\n\n#endif /* ALMANAC_H */\n\n"
  },
  {
    "path": "circle.csv",
    "content": "  0.0,-3813477.954, 3554276.552, 3662785.237\n  0.1,-3813477.599, 3554276.226, 3662785.918\n  0.2,-3813477.240, 3554275.906, 3662786.598\n  0.3,-3813476.876, 3554275.590, 3662787.278\n  0.4,-3813476.508, 3554275.280, 3662787.958\n  0.5,-3813476.135, 3554274.975, 3662788.638\n  0.6,-3813475.757, 3554274.675, 3662789.318\n  0.7,-3813475.375, 3554274.381, 3662789.997\n  0.8,-3813474.988, 3554274.091, 3662790.676\n  0.9,-3813474.597, 3554273.807, 3662791.355\n  1.0,-3813474.201, 3554273.528, 3662792.033\n  1.1,-3813473.800, 3554273.255, 3662792.711\n  1.2,-3813473.396, 3554272.986, 3662793.388\n  1.3,-3813472.986, 3554272.723, 3662794.065\n  1.4,-3813472.573, 3554272.466, 3662794.741\n  1.5,-3813472.155, 3554272.213, 3662795.416\n  1.6,-3813471.733, 3554271.967, 3662796.091\n  1.7,-3813471.306, 3554271.725, 3662796.764\n  1.8,-3813470.875, 3554271.489, 3662797.438\n  1.9,-3813470.440, 3554271.258, 3662798.110\n  2.0,-3813470.001, 3554271.033, 3662798.781\n  2.1,-3813469.557, 3554270.814, 3662799.452\n  2.2,-3813469.110, 3554270.599, 3662800.121\n  2.3,-3813468.658, 3554270.391, 3662800.790\n  2.4,-3813468.202, 3554270.187, 3662801.457\n  2.5,-3813467.742, 3554269.990, 3662802.123\n  2.6,-3813467.278, 3554269.798, 3662802.788\n  2.7,-3813466.810, 3554269.611, 3662803.452\n  2.8,-3813466.338, 3554269.430, 3662804.114\n  2.9,-3813465.862, 3554269.254, 3662804.776\n  3.0,-3813465.383, 3554269.084, 3662805.436\n  3.1,-3813464.899, 3554268.920, 3662806.094\n  3.2,-3813464.412, 3554268.761, 3662806.751\n  3.3,-3813463.920, 3554268.608, 3662807.407\n  3.4,-3813463.425, 3554268.461, 3662808.061\n  3.5,-3813462.927, 3554268.319, 3662808.713\n  3.6,-3813462.424, 3554268.183, 3662809.364\n  3.7,-3813461.918, 3554268.053, 3662810.013\n  3.8,-3813461.409, 3554267.928, 3662810.660\n  3.9,-3813460.895, 3554267.809, 3662811.306\n  4.0,-3813460.379, 3554267.695, 3662811.950\n  4.1,-3813459.858, 3554267.587, 3662812.592\n  4.2,-3813459.335, 3554267.485, 3662813.232\n  4.3,-3813458.807, 3554267.389, 3662813.870\n  4.4,-3813458.277, 3554267.298, 3662814.506\n  4.5,-3813457.743, 3554267.213, 3662815.140\n  4.6,-3813457.205, 3554267.134, 3662815.772\n  4.7,-3813456.665, 3554267.061, 3662816.402\n  4.8,-3813456.121, 3554266.993, 3662817.030\n  4.9,-3813455.574, 3554266.931, 3662817.655\n  5.0,-3813455.023, 3554266.875, 3662818.278\n  5.1,-3813454.470, 3554266.825, 3662818.899\n  5.2,-3813453.913, 3554266.780, 3662819.518\n  5.3,-3813453.354, 3554266.741, 3662820.134\n  5.4,-3813452.791, 3554266.708, 3662820.748\n  5.5,-3813452.226, 3554266.680, 3662821.359\n  5.6,-3813451.657, 3554266.659, 3662821.968\n  5.7,-3813451.085, 3554266.643, 3662822.575\n  5.8,-3813450.511, 3554266.633, 3662823.178\n  5.9,-3813449.934, 3554266.628, 3662823.779\n  6.0,-3813449.354, 3554266.630, 3662824.378\n  6.1,-3813448.771, 3554266.637, 3662824.973\n  6.2,-3813448.186, 3554266.650, 3662825.566\n  6.3,-3813447.598, 3554266.669, 3662826.156\n  6.4,-3813447.007, 3554266.693, 3662826.744\n  6.5,-3813446.414, 3554266.723, 3662827.328\n  6.6,-3813445.818, 3554266.759, 3662827.910\n  6.7,-3813445.220, 3554266.801, 3662828.488\n  6.8,-3813444.619, 3554266.849, 3662829.064\n  6.9,-3813444.016, 3554266.902, 3662829.636\n  7.0,-3813443.410, 3554266.961, 3662830.206\n  7.1,-3813442.802, 3554267.026, 3662830.772\n  7.2,-3813442.192, 3554267.096, 3662831.335\n  7.3,-3813441.579, 3554267.173, 3662831.895\n  7.4,-3813440.965, 3554267.255, 3662832.451\n  7.5,-3813440.348, 3554267.342, 3662833.005\n  7.6,-3813439.729, 3554267.436, 3662833.555\n  7.7,-3813439.108, 3554267.535, 3662834.102\n  7.8,-3813438.485, 3554267.640, 3662834.645\n  7.9,-3813437.859, 3554267.750, 3662835.185\n  8.0,-3813437.232, 3554267.867, 3662835.721\n  8.1,-3813436.603, 3554267.988, 3662836.254\n  8.2,-3813435.973, 3554268.116, 3662836.783\n  8.3,-3813435.340, 3554268.249, 3662837.309\n  8.4,-3813434.706, 3554268.388, 3662837.831\n  8.5,-3813434.069, 3554268.533, 3662838.350\n  8.6,-3813433.432, 3554268.683, 3662838.865\n  8.7,-3813432.792, 3554268.839, 3662839.376\n  8.8,-3813432.151, 3554269.000, 3662839.883\n  8.9,-3813431.508, 3554269.167, 3662840.387\n  9.0,-3813430.864, 3554269.340, 3662840.886\n  9.1,-3813430.219, 3554269.518, 3662841.382\n  9.2,-3813429.572, 3554269.702, 3662841.874\n  9.3,-3813428.923, 3554269.891, 3662842.362\n  9.4,-3813428.274, 3554270.086, 3662842.846\n  9.5,-3813427.623, 3554270.287, 3662843.326\n  9.6,-3813426.970, 3554270.493, 3662843.802\n  9.7,-3813426.317, 3554270.704, 3662844.274\n  9.8,-3813425.662, 3554270.921, 3662844.742\n  9.9,-3813425.007, 3554271.143, 3662845.206\n 10.0,-3813424.350, 3554271.371, 3662845.665\n 10.1,-3813423.692, 3554271.605, 3662846.121\n 10.2,-3813423.033, 3554271.843, 3662846.572\n 10.3,-3813422.374, 3554272.087, 3662847.019\n 10.4,-3813421.713, 3554272.337, 3662847.461\n 10.5,-3813421.052, 3554272.592, 3662847.900\n 10.6,-3813420.390, 3554272.852, 3662848.334\n 10.7,-3813419.727, 3554273.118, 3662848.763\n 10.8,-3813419.063, 3554273.389, 3662849.188\n 10.9,-3813418.399, 3554273.665, 3662849.609\n 11.0,-3813417.734, 3554273.946, 3662850.025\n 11.1,-3813417.069, 3554274.233, 3662850.437\n 11.2,-3813416.403, 3554274.525, 3662850.844\n 11.3,-3813415.737, 3554274.822, 3662851.247\n 11.4,-3813415.070, 3554275.125, 3662851.645\n 11.5,-3813414.403, 3554275.432, 3662852.038\n 11.6,-3813413.735, 3554275.745, 3662852.427\n 11.7,-3813413.068, 3554276.063, 3662852.811\n 11.8,-3813412.400, 3554276.386, 3662853.190\n 11.9,-3813411.731, 3554276.714, 3662853.565\n 12.0,-3813411.063, 3554277.047, 3662853.935\n 12.1,-3813410.395, 3554277.385, 3662854.300\n 12.2,-3813409.726, 3554277.728, 3662854.661\n 12.3,-3813409.058, 3554278.077, 3662855.016\n 12.4,-3813408.390, 3554278.430, 3662855.367\n 12.5,-3813407.721, 3554278.788, 3662855.713\n 12.6,-3813407.053, 3554279.151, 3662856.054\n 12.7,-3813406.385, 3554279.519, 3662856.390\n 12.8,-3813405.718, 3554279.892, 3662856.721\n 12.9,-3813405.050, 3554280.269, 3662857.047\n 13.0,-3813404.383, 3554280.652, 3662857.368\n 13.1,-3813403.717, 3554281.039, 3662857.684\n 13.2,-3813403.050, 3554281.431, 3662857.996\n 13.3,-3813402.384, 3554281.828, 3662858.302\n 13.4,-3813401.719, 3554282.230, 3662858.603\n 13.5,-3813401.054, 3554282.636, 3662858.899\n 13.6,-3813400.390, 3554283.047, 3662859.189\n 13.7,-3813399.727, 3554283.462, 3662859.475\n 13.8,-3813399.064, 3554283.882, 3662859.755\n 13.9,-3813398.402, 3554284.307, 3662860.031\n 14.0,-3813397.741, 3554284.736, 3662860.301\n 14.1,-3813397.080, 3554285.170, 3662860.566\n 14.2,-3813396.421, 3554285.608, 3662860.826\n 14.3,-3813395.762, 3554286.051, 3662861.080\n 14.4,-3813395.105, 3554286.498, 3662861.329\n 14.5,-3813394.448, 3554286.949, 3662861.573\n 14.6,-3813393.792, 3554287.405, 3662861.812\n 14.7,-3813393.138, 3554287.865, 3662862.045\n 14.8,-3813392.485, 3554288.330, 3662862.273\n 14.9,-3813391.833, 3554288.798, 3662862.495\n 15.0,-3813391.182, 3554289.271, 3662862.713\n 15.1,-3813390.532, 3554289.749, 3662862.924\n 15.2,-3813389.884, 3554290.230, 3662863.131\n 15.3,-3813389.237, 3554290.715, 3662863.332\n 15.4,-3813388.592, 3554291.205, 3662863.527\n 15.5,-3813387.948, 3554291.698, 3662863.718\n 15.6,-3813387.305, 3554292.196, 3662863.902\n 15.7,-3813386.664, 3554292.698, 3662864.082\n 15.8,-3813386.025, 3554293.203, 3662864.255\n 15.9,-3813385.388, 3554293.713, 3662864.424\n 16.0,-3813384.752, 3554294.226, 3662864.586\n 16.1,-3813384.118, 3554294.743, 3662864.744\n 16.2,-3813383.485, 3554295.264, 3662864.895\n 16.3,-3813382.855, 3554295.789, 3662865.042\n 16.4,-3813382.226, 3554296.318, 3662865.182\n 16.5,-3813381.599, 3554296.850, 3662865.318\n 16.6,-3813380.974, 3554297.386, 3662865.447\n 16.7,-3813380.351, 3554297.925, 3662865.571\n 16.8,-3813379.731, 3554298.469, 3662865.690\n 16.9,-3813379.112, 3554299.015, 3662865.802\n 17.0,-3813378.495, 3554299.566, 3662865.910\n 17.1,-3813377.881, 3554300.119, 3662866.011\n 17.2,-3813377.269, 3554300.676, 3662866.107\n 17.3,-3813376.659, 3554301.237, 3662866.198\n 17.4,-3813376.051, 3554301.801, 3662866.283\n 17.5,-3813375.446, 3554302.368, 3662866.362\n 17.6,-3813374.843, 3554302.939, 3662866.435\n 17.7,-3813374.243, 3554303.513, 3662866.503\n 17.8,-3813373.644, 3554304.090, 3662866.565\n 17.9,-3813373.049, 3554304.670, 3662866.622\n 18.0,-3813372.456, 3554305.253, 3662866.673\n 18.1,-3813371.866, 3554305.840, 3662866.718\n 18.2,-3813371.278, 3554306.429, 3662866.758\n 18.3,-3813370.693, 3554307.021, 3662866.792\n 18.4,-3813370.111, 3554307.617, 3662866.820\n 18.5,-3813369.531, 3554308.215, 3662866.843\n 18.6,-3813368.954, 3554308.816, 3662866.860\n 18.7,-3813368.380, 3554309.420, 3662866.871\n 18.8,-3813367.809, 3554310.027, 3662866.877\n 18.9,-3813367.241, 3554310.637, 3662866.877\n 19.0,-3813366.676, 3554311.249, 3662866.871\n 19.1,-3813366.114, 3554311.864, 3662866.860\n 19.2,-3813365.554, 3554312.482, 3662866.843\n 19.3,-3813364.998, 3554313.102, 3662866.820\n 19.4,-3813364.445, 3554313.725, 3662866.792\n 19.5,-3813363.895, 3554314.350, 3662866.758\n 19.6,-3813363.349, 3554314.978, 3662866.718\n 19.7,-3813362.805, 3554315.608, 3662866.673\n 19.8,-3813362.265, 3554316.240, 3662866.622\n 19.9,-3813361.728, 3554316.875, 3662866.565\n 20.0,-3813361.195, 3554317.512, 3662866.503\n 20.1,-3813360.664, 3554318.152, 3662866.435\n 20.2,-3813360.138, 3554318.793, 3662866.361\n 20.3,-3813359.614, 3554319.437, 3662866.282\n 20.4,-3813359.094, 3554320.082, 3662866.197\n 20.5,-3813358.578, 3554320.730, 3662866.106\n 20.6,-3813358.065, 3554321.380, 3662866.010\n 20.7,-3813357.556, 3554322.032, 3662865.909\n 20.8,-3813357.051, 3554322.686, 3662865.801\n 20.9,-3813356.549, 3554323.341, 3662865.689\n 21.0,-3813356.050, 3554323.999, 3662865.570\n 21.1,-3813355.556, 3554324.658, 3662865.446\n 21.2,-3813355.065, 3554325.319, 3662865.316\n 21.3,-3813354.578, 3554325.981, 3662865.181\n 21.4,-3813354.095, 3554326.646, 3662865.040\n 21.5,-3813353.616, 3554327.312, 3662864.894\n 21.6,-3813353.141, 3554327.979, 3662864.742\n 21.7,-3813352.669, 3554328.648, 3662864.585\n 21.8,-3813352.202, 3554329.318, 3662864.422\n 21.9,-3813351.739, 3554329.990, 3662864.254\n 22.0,-3813351.279, 3554330.663, 3662864.080\n 22.1,-3813350.824, 3554331.338, 3662863.901\n 22.2,-3813350.373, 3554332.014, 3662863.716\n 22.3,-3813349.926, 3554332.691, 3662863.526\n 22.4,-3813349.483, 3554333.369, 3662863.330\n 22.5,-3813349.044, 3554334.048, 3662863.129\n 22.6,-3813348.609, 3554334.729, 3662862.923\n 22.7,-3813348.179, 3554335.410, 3662862.711\n 22.8,-3813347.753, 3554336.093, 3662862.493\n 22.9,-3813347.331, 3554336.776, 3662862.271\n 23.0,-3813346.914, 3554337.460, 3662862.043\n 23.1,-3813346.501, 3554338.146, 3662861.809\n 23.2,-3813346.092, 3554338.831, 3662861.571\n 23.3,-3813345.688, 3554339.518, 3662861.327\n 23.4,-3813345.288, 3554340.206, 3662861.078\n 23.5,-3813344.893, 3554340.894, 3662860.823\n 23.6,-3813344.502, 3554341.582, 3662860.564\n 23.7,-3813344.116, 3554342.272, 3662860.299\n 23.8,-3813343.735, 3554342.961, 3662860.028\n 23.9,-3813343.357, 3554343.652, 3662859.753\n 24.0,-3813342.985, 3554344.342, 3662859.472\n 24.1,-3813342.617, 3554345.033, 3662859.187\n 24.2,-3813342.254, 3554345.725, 3662858.896\n 24.3,-3813341.896, 3554346.416, 3662858.600\n 24.4,-3813341.542, 3554347.108, 3662858.299\n 24.5,-3813341.193, 3554347.800, 3662857.993\n 24.6,-3813340.849, 3554348.492, 3662857.682\n 24.7,-3813340.509, 3554349.185, 3662857.366\n 24.8,-3813340.174, 3554349.877, 3662857.044\n 24.9,-3813339.845, 3554350.569, 3662856.718\n 25.0,-3813339.520, 3554351.261, 3662856.387\n 25.1,-3813339.199, 3554351.954, 3662856.051\n 25.2,-3813338.884, 3554352.646, 3662855.710\n 25.3,-3813338.574, 3554353.337, 3662855.364\n 25.4,-3813338.269, 3554354.029, 3662855.013\n 25.5,-3813337.968, 3554354.720, 3662854.658\n 25.6,-3813337.673, 3554355.411, 3662854.297\n 25.7,-3813337.383, 3554356.101, 3662853.932\n 25.8,-3813337.097, 3554356.791, 3662853.562\n 25.9,-3813336.817, 3554357.481, 3662853.187\n 26.0,-3813336.542, 3554358.170, 3662852.808\n 26.1,-3813336.272, 3554358.858, 3662852.423\n 26.2,-3813336.006, 3554359.546, 3662852.035\n 26.3,-3813335.747, 3554360.233, 3662851.641\n 26.4,-3813335.492, 3554360.919, 3662851.243\n 26.5,-3813335.242, 3554361.605, 3662850.840\n 26.6,-3813334.998, 3554362.290, 3662850.433\n 26.7,-3813334.758, 3554362.973, 3662850.021\n 26.8,-3813334.524, 3554363.656, 3662849.605\n 26.9,-3813334.296, 3554364.338, 3662849.185\n 27.0,-3813334.072, 3554365.019, 3662848.759\n 27.1,-3813333.854, 3554365.699, 3662848.330\n 27.2,-3813333.641, 3554366.378, 3662847.896\n 27.3,-3813333.433, 3554367.056, 3662847.458\n 27.4,-3813333.230, 3554367.732, 3662847.015\n 27.5,-3813333.033, 3554368.407, 3662846.568\n 27.6,-3813332.841, 3554369.081, 3662846.117\n 27.7,-3813332.655, 3554369.754, 3662845.661\n 27.8,-3813332.474, 3554370.425, 3662845.202\n 27.9,-3813332.298, 3554371.094, 3662844.738\n 28.0,-3813332.128, 3554371.763, 3662844.270\n 28.1,-3813331.963, 3554372.429, 3662843.798\n 28.2,-3813331.803, 3554373.094, 3662843.322\n 28.3,-3813331.649, 3554373.758, 3662842.842\n 28.4,-3813331.500, 3554374.420, 3662842.358\n 28.5,-3813331.357, 3554375.080, 3662841.870\n 28.6,-3813331.219, 3554375.738, 3662841.378\n 28.7,-3813331.087, 3554376.395, 3662840.882\n 28.8,-3813330.960, 3554377.049, 3662840.382\n 28.9,-3813330.838, 3554377.702, 3662839.879\n 29.0,-3813330.722, 3554378.353, 3662839.371\n 29.1,-3813330.612, 3554379.002, 3662838.860\n 29.2,-3813330.507, 3554379.648, 3662838.345\n 29.3,-3813330.407, 3554380.293, 3662837.827\n 29.4,-3813330.313, 3554380.936, 3662837.305\n 29.5,-3813330.225, 3554381.576, 3662836.779\n 29.6,-3813330.142, 3554382.214, 3662836.249\n 29.7,-3813330.065, 3554382.850, 3662835.716\n 29.8,-3813329.993, 3554383.484, 3662835.180\n 29.9,-3813329.926, 3554384.115, 3662834.640\n 30.0,-3813329.866, 3554384.744, 3662834.097\n 30.1,-3813329.810, 3554385.371, 3662833.550\n 30.2,-3813329.761, 3554385.995, 3662833.000\n 30.3,-3813329.717, 3554386.616, 3662832.446\n 30.4,-3813329.678, 3554387.235, 3662831.890\n 30.5,-3813329.645, 3554387.851, 3662831.330\n 30.6,-3813329.618, 3554388.465, 3662830.767\n 30.7,-3813329.596, 3554389.076, 3662830.200\n 30.8,-3813329.579, 3554389.684, 3662829.631\n 30.9,-3813329.569, 3554390.290, 3662829.059\n 31.0,-3813329.563, 3554390.892, 3662828.483\n 31.1,-3813329.564, 3554391.492, 3662827.904\n 31.2,-3813329.570, 3554392.089, 3662827.323\n 31.3,-3813329.581, 3554392.683, 3662826.739\n 31.4,-3813329.598, 3554393.274, 3662826.151\n 31.5,-3813329.621, 3554393.862, 3662825.561\n 31.6,-3813329.649, 3554394.446, 3662824.968\n 31.7,-3813329.683, 3554395.028, 3662824.372\n 31.8,-3813329.723, 3554395.607, 3662823.774\n 31.9,-3813329.768, 3554396.182, 3662823.173\n 32.0,-3813329.818, 3554396.754, 3662822.569\n 32.1,-3813329.874, 3554397.323, 3662821.963\n 32.2,-3813329.936, 3554397.889, 3662821.354\n 32.3,-3813330.003, 3554398.451, 3662820.743\n 32.4,-3813330.075, 3554399.010, 3662820.129\n 32.5,-3813330.154, 3554399.566, 3662819.512\n 32.6,-3813330.237, 3554400.118, 3662818.894\n 32.7,-3813330.327, 3554400.666, 3662818.273\n 32.8,-3813330.421, 3554401.211, 3662817.650\n 32.9,-3813330.522, 3554401.752, 3662817.024\n 33.0,-3813330.627, 3554402.290, 3662816.396\n 33.1,-3813330.739, 3554402.824, 3662815.766\n 33.2,-3813330.855, 3554403.355, 3662815.134\n 33.3,-3813330.978, 3554403.881, 3662814.500\n 33.4,-3813331.105, 3554404.404, 3662813.864\n 33.5,-3813331.239, 3554404.923, 3662813.226\n 33.6,-3813331.377, 3554405.439, 3662812.586\n 33.7,-3813331.521, 3554405.950, 3662811.944\n 33.8,-3813331.671, 3554406.458, 3662811.300\n 33.9,-3813331.826, 3554406.961, 3662810.654\n 34.0,-3813331.986, 3554407.461, 3662810.007\n 34.1,-3813332.152, 3554407.956, 3662809.358\n 34.2,-3813332.323, 3554408.448, 3662808.707\n 34.3,-3813332.500, 3554408.935, 3662808.055\n 34.4,-3813332.681, 3554409.419, 3662807.401\n 34.5,-3813332.869, 3554409.898, 3662806.745\n 34.6,-3813333.061, 3554410.373, 3662806.088\n 34.7,-3813333.259, 3554410.844, 3662805.430\n 34.8,-3813333.462, 3554411.310, 3662804.770\n 34.9,-3813333.671, 3554411.773, 3662804.109\n 35.0,-3813333.885, 3554412.231, 3662803.446\n 35.1,-3813334.104, 3554412.684, 3662802.782\n 35.2,-3813334.328, 3554413.134, 3662802.117\n 35.3,-3813334.558, 3554413.579, 3662801.451\n 35.4,-3813334.792, 3554414.019, 3662800.784\n 35.5,-3813335.032, 3554414.455, 3662800.115\n 35.6,-3813335.278, 3554414.886, 3662799.446\n 35.7,-3813335.528, 3554415.313, 3662798.775\n 35.8,-3813335.784, 3554415.736, 3662798.104\n 35.9,-3813336.044, 3554416.153, 3662797.432\n 36.0,-3813336.310, 3554416.567, 3662796.759\n 36.1,-3813336.581, 3554416.975, 3662796.085\n 36.2,-3813336.857, 3554417.379, 3662795.410\n 36.3,-3813337.138, 3554417.778, 3662794.735\n 36.4,-3813337.424, 3554418.173, 3662794.059\n 36.5,-3813337.715, 3554418.562, 3662793.382\n 36.6,-3813338.011, 3554418.947, 3662792.705\n 36.7,-3813338.312, 3554419.327, 3662792.027\n 36.8,-3813338.618, 3554419.703, 3662791.349\n 36.9,-3813338.929, 3554420.073, 3662790.670\n 37.0,-3813339.245, 3554420.438, 3662789.991\n 37.1,-3813339.566, 3554420.799, 3662789.312\n 37.2,-3813339.892, 3554421.155, 3662788.632\n 37.3,-3813340.222, 3554421.505, 3662787.952\n 37.4,-3813340.557, 3554421.851, 3662787.272\n 37.5,-3813340.898, 3554422.192, 3662786.592\n 37.6,-3813341.243, 3554422.528, 3662785.912\n 37.7,-3813341.592, 3554422.858, 3662785.231\n 37.8,-3813341.947, 3554423.184, 3662784.551\n 37.9,-3813342.306, 3554423.504, 3662783.871\n 38.0,-3813342.670, 3554423.819, 3662783.191\n 38.1,-3813343.038, 3554424.130, 3662782.511\n 38.2,-3813343.411, 3554424.435, 3662781.831\n 38.3,-3813343.789, 3554424.734, 3662781.151\n 38.4,-3813344.171, 3554425.029, 3662780.472\n 38.5,-3813344.558, 3554425.318, 3662779.793\n 38.6,-3813344.950, 3554425.602, 3662779.114\n 38.7,-3813345.346, 3554425.881, 3662778.436\n 38.8,-3813345.746, 3554426.155, 3662777.758\n 38.9,-3813346.151, 3554426.423, 3662777.081\n 39.0,-3813346.560, 3554426.686, 3662776.404\n 39.1,-3813346.974, 3554426.943, 3662775.728\n 39.2,-3813347.392, 3554427.196, 3662775.053\n 39.3,-3813347.814, 3554427.442, 3662774.378\n 39.4,-3813348.241, 3554427.684, 3662773.704\n 39.5,-3813348.672, 3554427.920, 3662773.031\n 39.6,-3813349.107, 3554428.150, 3662772.359\n 39.7,-3813349.546, 3554428.376, 3662771.688\n 39.8,-3813349.990, 3554428.595, 3662771.017\n 39.9,-3813350.437, 3554428.809, 3662770.348\n 40.0,-3813350.889, 3554429.018, 3662769.680\n 40.1,-3813351.345, 3554429.221, 3662769.012\n 40.2,-3813351.805, 3554429.419, 3662768.346\n 40.3,-3813352.269, 3554429.611, 3662767.681\n 40.4,-3813352.737, 3554429.798, 3662767.017\n 40.5,-3813353.209, 3554429.979, 3662766.355\n 40.6,-3813353.685, 3554430.154, 3662765.693\n 40.7,-3813354.164, 3554430.324, 3662765.034\n 40.8,-3813354.648, 3554430.488, 3662764.375\n 40.9,-3813355.136, 3554430.647, 3662763.718\n 41.0,-3813355.627, 3554430.800, 3662763.063\n 41.1,-3813356.122, 3554430.947, 3662762.409\n 41.2,-3813356.620, 3554431.089, 3662761.756\n 41.3,-3813357.123, 3554431.225, 3662761.105\n 41.4,-3813357.629, 3554431.356, 3662760.456\n 41.5,-3813358.139, 3554431.480, 3662759.809\n 41.6,-3813358.652, 3554431.599, 3662759.163\n 41.7,-3813359.169, 3554431.713, 3662758.520\n 41.8,-3813359.689, 3554431.821, 3662757.878\n 41.9,-3813360.213, 3554431.923, 3662757.238\n 42.0,-3813360.740, 3554432.019, 3662756.600\n 42.1,-3813361.271, 3554432.109, 3662755.963\n 42.2,-3813361.805, 3554432.194, 3662755.329\n 42.3,-3813362.342, 3554432.273, 3662754.697\n 42.4,-3813362.883, 3554432.347, 3662754.068\n 42.5,-3813363.427, 3554432.414, 3662753.440\n 42.6,-3813363.974, 3554432.476, 3662752.814\n 42.7,-3813364.524, 3554432.532, 3662752.191\n 42.8,-3813365.078, 3554432.583, 3662751.570\n 42.9,-3813365.634, 3554432.628, 3662750.952\n 43.0,-3813366.194, 3554432.666, 3662750.335\n 43.1,-3813366.757, 3554432.700, 3662749.721\n 43.2,-3813367.322, 3554432.727, 3662749.110\n 43.3,-3813367.891, 3554432.749, 3662748.501\n 43.4,-3813368.462, 3554432.764, 3662747.895\n 43.5,-3813369.037, 3554432.774, 3662747.291\n 43.6,-3813369.614, 3554432.779, 3662746.690\n 43.7,-3813370.194, 3554432.777, 3662746.092\n 43.8,-3813370.777, 3554432.770, 3662745.496\n 43.9,-3813371.362, 3554432.757, 3662744.903\n 44.0,-3813371.950, 3554432.738, 3662744.313\n 44.1,-3813372.541, 3554432.714, 3662743.726\n 44.2,-3813373.134, 3554432.683, 3662743.142\n 44.3,-3813373.730, 3554432.647, 3662742.560\n 44.4,-3813374.329, 3554432.605, 3662741.982\n 44.5,-3813374.929, 3554432.558, 3662741.406\n 44.6,-3813375.533, 3554432.505, 3662740.834\n 44.7,-3813376.138, 3554432.445, 3662740.264\n 44.8,-3813376.746, 3554432.381, 3662739.698\n 44.9,-3813377.356, 3554432.310, 3662739.135\n 45.0,-3813377.969, 3554432.234, 3662738.575\n 45.1,-3813378.584, 3554432.152, 3662738.019\n 45.2,-3813379.201, 3554432.064, 3662737.465\n 45.3,-3813379.820, 3554431.970, 3662736.915\n 45.4,-3813380.441, 3554431.871, 3662736.369\n 45.5,-3813381.064, 3554431.766, 3662735.825\n 45.6,-3813381.689, 3554431.656, 3662735.285\n 45.7,-3813382.316, 3554431.539, 3662734.749\n 45.8,-3813382.945, 3554431.417, 3662734.216\n 45.9,-3813383.576, 3554431.290, 3662733.687\n 46.0,-3813384.208, 3554431.156, 3662733.161\n 46.1,-3813384.843, 3554431.017, 3662732.639\n 46.2,-3813385.479, 3554430.873, 3662732.120\n 46.3,-3813386.117, 3554430.723, 3662731.606\n 46.4,-3813386.756, 3554430.567, 3662731.095\n 46.5,-3813387.397, 3554430.405, 3662730.587\n 46.6,-3813388.040, 3554430.238, 3662730.084\n 46.7,-3813388.684, 3554430.065, 3662729.584\n 46.8,-3813389.330, 3554429.887, 3662729.088\n 46.9,-3813389.977, 3554429.703, 3662728.596\n 47.0,-3813390.625, 3554429.514, 3662728.108\n 47.1,-3813391.275, 3554429.319, 3662727.624\n 47.2,-3813391.926, 3554429.118, 3662727.144\n 47.3,-3813392.578, 3554428.912, 3662726.668\n 47.4,-3813393.232, 3554428.701, 3662726.196\n 47.5,-3813393.886, 3554428.484, 3662725.729\n 47.6,-3813394.542, 3554428.261, 3662725.265\n 47.7,-3813395.199, 3554428.034, 3662724.805\n 47.8,-3813395.857, 3554427.800, 3662724.350\n 47.9,-3813396.515, 3554427.561, 3662723.899\n 48.0,-3813397.175, 3554427.317, 3662723.452\n 48.1,-3813397.836, 3554427.068, 3662723.010\n 48.2,-3813398.497, 3554426.813, 3662722.571\n 48.3,-3813399.159, 3554426.553, 3662722.138\n 48.4,-3813399.822, 3554426.287, 3662721.708\n 48.5,-3813400.486, 3554426.016, 3662721.283\n 48.6,-3813401.150, 3554425.740, 3662720.862\n 48.7,-3813401.815, 3554425.458, 3662720.446\n 48.8,-3813402.480, 3554425.171, 3662720.034\n 48.9,-3813403.146, 3554424.879, 3662719.627\n 49.0,-3813403.812, 3554424.582, 3662719.225\n 49.1,-3813404.479, 3554424.280, 3662718.827\n 49.2,-3813405.146, 3554423.972, 3662718.433\n 49.3,-3813405.814, 3554423.659, 3662718.045\n 49.4,-3813406.481, 3554423.341, 3662717.661\n 49.5,-3813407.149, 3554423.018, 3662717.281\n 49.6,-3813407.817, 3554422.690, 3662716.906\n 49.7,-3813408.486, 3554422.357, 3662716.537\n 49.8,-3813409.154, 3554422.019, 3662716.171\n 49.9,-3813409.822, 3554421.675, 3662715.811\n 50.0,-3813410.491, 3554421.327, 3662715.456\n 50.1,-3813411.159, 3554420.974, 3662715.105\n 50.2,-3813411.827, 3554420.616, 3662714.759\n 50.3,-3813412.495, 3554420.253, 3662714.418\n 50.4,-3813413.163, 3554419.885, 3662714.082\n 50.5,-3813413.831, 3554419.512, 3662713.751\n 50.6,-3813414.498, 3554419.134, 3662713.425\n 50.7,-3813415.166, 3554418.752, 3662713.104\n 50.8,-3813415.832, 3554418.364, 3662712.788\n 50.9,-3813416.498, 3554417.972, 3662712.477\n 51.0,-3813417.164, 3554417.575, 3662712.171\n 51.1,-3813417.830, 3554417.174, 3662711.870\n 51.2,-3813418.494, 3554416.767, 3662711.574\n 51.3,-3813419.158, 3554416.357, 3662711.283\n 51.4,-3813419.822, 3554415.941, 3662710.997\n 51.5,-3813420.485, 3554415.521, 3662710.717\n 51.6,-3813421.147, 3554415.096, 3662710.442\n 51.7,-3813421.808, 3554414.667, 3662710.172\n 51.8,-3813422.468, 3554414.233, 3662709.907\n 51.9,-3813423.128, 3554413.795, 3662709.647\n 52.0,-3813423.787, 3554413.352, 3662709.393\n 52.1,-3813424.444, 3554412.905, 3662709.144\n 52.2,-3813425.101, 3554412.454, 3662708.900\n 52.3,-3813425.756, 3554411.998, 3662708.661\n 52.4,-3813426.411, 3554411.538, 3662708.428\n 52.5,-3813427.064, 3554411.073, 3662708.200\n 52.6,-3813427.716, 3554410.604, 3662707.978\n 52.7,-3813428.367, 3554410.131, 3662707.761\n 52.8,-3813429.016, 3554409.654, 3662707.549\n 52.9,-3813429.665, 3554409.173, 3662707.342\n 53.0,-3813430.311, 3554408.687, 3662707.141\n 53.1,-3813430.957, 3554408.198, 3662706.946\n 53.2,-3813431.601, 3554407.704, 3662706.756\n 53.3,-3813432.243, 3554407.207, 3662706.571\n 53.4,-3813432.884, 3554406.705, 3662706.392\n 53.5,-3813433.523, 3554406.199, 3662706.218\n 53.6,-3813434.161, 3554405.690, 3662706.050\n 53.7,-3813434.797, 3554405.176, 3662705.887\n 53.8,-3813435.431, 3554404.659, 3662705.730\n 53.9,-3813436.063, 3554404.138, 3662705.578\n 54.0,-3813436.694, 3554403.613, 3662705.432\n 54.1,-3813437.323, 3554403.085, 3662705.291\n 54.2,-3813437.949, 3554402.552, 3662705.156\n 54.3,-3813438.574, 3554402.016, 3662705.027\n 54.4,-3813439.197, 3554401.477, 3662704.903\n 54.5,-3813439.818, 3554400.934, 3662704.784\n 54.6,-3813440.436, 3554400.387, 3662704.672\n 54.7,-3813441.053, 3554399.836, 3662704.564\n 54.8,-3813441.667, 3554399.283, 3662704.463\n 54.9,-3813442.280, 3554398.726, 3662704.367\n 55.0,-3813442.889, 3554398.165, 3662704.276\n 55.1,-3813443.497, 3554397.601, 3662704.192\n 55.2,-3813444.102, 3554397.034, 3662704.113\n 55.3,-3813444.705, 3554396.463, 3662704.039\n 55.4,-3813445.306, 3554395.889, 3662703.971\n 55.5,-3813445.904, 3554395.312, 3662703.909\n 55.6,-3813446.499, 3554394.732, 3662703.853\n 55.7,-3813447.092, 3554394.149, 3662703.802\n 55.8,-3813447.682, 3554393.562, 3662703.756\n 55.9,-3813448.270, 3554392.973, 3662703.717\n 56.0,-3813448.855, 3554392.380, 3662703.683\n 56.1,-3813449.437, 3554391.785, 3662703.655\n 56.2,-3813450.017, 3554391.186, 3662703.632\n 56.3,-3813450.594, 3554390.585, 3662703.615\n 56.4,-3813451.168, 3554389.981, 3662703.604\n 56.5,-3813451.739, 3554389.374, 3662703.598\n 56.6,-3813452.307, 3554388.765, 3662703.598\n 56.7,-3813452.872, 3554388.152, 3662703.604\n 56.8,-3813453.434, 3554387.537, 3662703.615\n 56.9,-3813453.993, 3554386.920, 3662703.633\n 57.0,-3813454.550, 3554386.299, 3662703.655\n 57.1,-3813455.103, 3554385.677, 3662703.684\n 57.2,-3813455.652, 3554385.051, 3662703.718\n 57.3,-3813456.199, 3554384.424, 3662703.757\n 57.4,-3813456.742, 3554383.793, 3662703.803\n 57.5,-3813457.283, 3554383.161, 3662703.854\n 57.6,-3813457.819, 3554382.526, 3662703.911\n 57.7,-3813458.353, 3554381.889, 3662703.973\n 57.8,-3813458.883, 3554381.250, 3662704.041\n 57.9,-3813459.410, 3554380.608, 3662704.115\n 58.0,-3813459.933, 3554379.965, 3662704.194\n 58.1,-3813460.453, 3554379.319, 3662704.279\n 58.2,-3813460.969, 3554378.671, 3662704.369\n 58.3,-3813461.482, 3554378.021, 3662704.465\n 58.4,-3813461.991, 3554377.369, 3662704.567\n 58.5,-3813462.497, 3554376.716, 3662704.675\n 58.6,-3813462.999, 3554376.060, 3662704.787\n 58.7,-3813463.497, 3554375.402, 3662704.906\n 58.8,-3813463.991, 3554374.743, 3662705.030\n 58.9,-3813464.482, 3554374.082, 3662705.160\n 59.0,-3813464.969, 3554373.420, 3662705.295\n 59.1,-3813465.452, 3554372.755, 3662705.436\n 59.2,-3813465.931, 3554372.089, 3662705.582\n 59.3,-3813466.406, 3554371.422, 3662705.734\n 59.4,-3813466.878, 3554370.753, 3662705.891\n 59.5,-3813467.345, 3554370.083, 3662706.054\n 59.6,-3813467.808, 3554369.411, 3662706.223\n 59.7,-3813468.268, 3554368.738, 3662706.397\n 59.8,-3813468.723, 3554368.063, 3662706.576\n 59.9,-3813469.174, 3554367.387, 3662706.761\n 60.0,-3813469.621, 3554366.710, 3662706.951\n 60.1,-3813470.064, 3554366.032, 3662707.147\n 60.2,-3813470.503, 3554365.353, 3662707.348\n 60.3,-3813470.937, 3554364.672, 3662707.554\n 60.4,-3813471.368, 3554363.991, 3662707.766\n 60.5,-3813471.793, 3554363.308, 3662707.984\n 60.6,-3813472.215, 3554362.625, 3662708.206\n 60.7,-3813472.632, 3554361.940, 3662708.434\n 60.8,-3813473.045, 3554361.255, 3662708.668\n 60.9,-3813473.454, 3554360.569, 3662708.906\n 61.0,-3813473.858, 3554359.883, 3662709.150\n 61.1,-3813474.258, 3554359.195, 3662709.399\n 61.2,-3813474.653, 3554358.507, 3662709.654\n 61.3,-3813475.044, 3554357.818, 3662709.914\n 61.4,-3813475.430, 3554357.129, 3662710.179\n 61.5,-3813475.812, 3554356.439, 3662710.449\n 61.6,-3813476.189, 3554355.749, 3662710.724\n 61.7,-3813476.561, 3554355.059, 3662711.005\n 61.8,-3813476.929, 3554354.367, 3662711.291\n 61.9,-3813477.292, 3554353.676, 3662711.582\n 62.0,-3813477.650, 3554352.984, 3662711.878\n 62.1,-3813478.004, 3554352.293, 3662712.179\n 62.2,-3813478.353, 3554351.601, 3662712.485\n 62.3,-3813478.697, 3554350.908, 3662712.796\n 62.4,-3813479.037, 3554350.216, 3662713.112\n 62.5,-3813479.371, 3554349.524, 3662713.434\n 62.6,-3813479.701, 3554348.832, 3662713.760\n 62.7,-3813480.026, 3554348.139, 3662714.091\n 62.8,-3813480.346, 3554347.447, 3662714.427\n 62.9,-3813480.661, 3554346.755, 3662714.768\n 63.0,-3813480.972, 3554346.064, 3662715.114\n 63.1,-3813481.277, 3554345.372, 3662715.465\n 63.2,-3813481.577, 3554344.681, 3662715.821\n 63.3,-3813481.873, 3554343.990, 3662716.181\n 63.4,-3813482.163, 3554343.300, 3662716.546\n 63.5,-3813482.448, 3554342.610, 3662716.916\n 63.6,-3813482.728, 3554341.920, 3662717.291\n 63.7,-3813483.004, 3554341.231, 3662717.671\n 63.8,-3813483.274, 3554340.543, 3662718.055\n 63.9,-3813483.539, 3554339.855, 3662718.444\n 64.0,-3813483.799, 3554339.168, 3662718.837\n 64.1,-3813484.053, 3554338.482, 3662719.235\n 64.2,-3813484.303, 3554337.796, 3662719.638\n 64.3,-3813484.547, 3554337.111, 3662720.045\n 64.4,-3813484.786, 3554336.427, 3662720.457\n 64.5,-3813485.020, 3554335.744, 3662720.873\n 64.6,-3813485.249, 3554335.063, 3662721.294\n 64.7,-3813485.473, 3554334.382, 3662721.719\n 64.8,-3813485.691, 3554333.702, 3662722.149\n 64.9,-3813485.904, 3554333.023, 3662722.583\n 65.0,-3813486.112, 3554332.345, 3662723.021\n 65.1,-3813486.314, 3554331.669, 3662723.464\n 65.2,-3813486.511, 3554330.994, 3662723.911\n 65.3,-3813486.703, 3554330.320, 3662724.362\n 65.4,-3813486.889, 3554329.647, 3662724.818\n 65.5,-3813487.071, 3554328.976, 3662725.277\n 65.6,-3813487.246, 3554328.307, 3662725.741\n 65.7,-3813487.417, 3554327.638, 3662726.209\n 65.8,-3813487.581, 3554326.972, 3662726.681\n 65.9,-3813487.741, 3554326.307, 3662727.157\n 66.0,-3813487.895, 3554325.643, 3662727.637\n 66.1,-3813488.044, 3554324.981, 3662728.121\n 66.2,-3813488.187, 3554324.321, 3662728.609\n 66.3,-3813488.325, 3554323.663, 3662729.101\n 66.4,-3813488.457, 3554323.007, 3662729.597\n 66.5,-3813488.584, 3554322.352, 3662730.097\n 66.6,-3813488.706, 3554321.699, 3662730.601\n 66.7,-3813488.821, 3554321.048, 3662731.108\n 66.8,-3813488.932, 3554320.400, 3662731.619\n 66.9,-3813489.037, 3554319.753, 3662732.134\n 67.0,-3813489.136, 3554319.108, 3662732.653\n 67.1,-3813489.230, 3554318.466, 3662733.175\n 67.2,-3813489.319, 3554317.825, 3662733.701\n 67.3,-3813489.402, 3554317.187, 3662734.230\n 67.4,-3813489.479, 3554316.551, 3662734.763\n 67.5,-3813489.551, 3554315.917, 3662735.300\n 67.6,-3813489.617, 3554315.286, 3662735.840\n 67.7,-3813489.678, 3554314.657, 3662736.383\n 67.8,-3813489.733, 3554314.031, 3662736.930\n 67.9,-3813489.783, 3554313.407, 3662737.480\n 68.0,-3813489.827, 3554312.785, 3662738.033\n 68.1,-3813489.865, 3554312.167, 3662738.590\n 68.2,-3813489.898, 3554311.550, 3662739.150\n 68.3,-3813489.925, 3554310.937, 3662739.713\n 68.4,-3813489.947, 3554310.326, 3662740.280\n 68.5,-3813489.964, 3554309.717, 3662740.849\n 68.6,-3813489.974, 3554309.112, 3662741.421\n 68.7,-3813489.979, 3554308.509, 3662741.997\n 68.8,-3813489.979, 3554307.910, 3662742.576\n 68.9,-3813489.973, 3554307.313, 3662743.157\n 69.0,-3813489.961, 3554306.719, 3662743.742\n 69.1,-3813489.944, 3554306.128, 3662744.329\n 69.2,-3813489.921, 3554305.540, 3662744.919\n 69.3,-3813489.893, 3554304.955, 3662745.512\n 69.4,-3813489.859, 3554304.374, 3662746.108\n 69.5,-3813489.820, 3554303.795, 3662746.706\n 69.6,-3813489.775, 3554303.220, 3662747.307\n 69.7,-3813489.724, 3554302.647, 3662747.911\n 69.8,-3813489.668, 3554302.079, 3662748.517\n 69.9,-3813489.607, 3554301.513, 3662749.126\n 70.0,-3813489.539, 3554300.951, 3662749.738\n 70.1,-3813489.467, 3554300.392, 3662750.352\n 70.2,-3813489.389, 3554299.836, 3662750.968\n 70.3,-3813489.305, 3554299.285, 3662751.587\n 70.4,-3813489.215, 3554298.736, 3662752.208\n 70.5,-3813489.121, 3554298.191, 3662752.831\n 70.6,-3813489.020, 3554297.650, 3662753.457\n 70.7,-3813488.914, 3554297.112, 3662754.084\n 70.8,-3813488.803, 3554296.578, 3662754.714\n 70.9,-3813488.686, 3554296.048, 3662755.346\n 71.0,-3813488.564, 3554295.521, 3662755.980\n 71.1,-3813488.436, 3554294.998, 3662756.617\n 71.2,-3813488.303, 3554294.479, 3662757.255\n 71.3,-3813488.164, 3554293.964, 3662757.895\n 71.4,-3813488.020, 3554293.452, 3662758.537\n 71.5,-3813487.871, 3554292.945, 3662759.181\n 71.6,-3813487.716, 3554292.441, 3662759.826\n 71.7,-3813487.555, 3554291.942, 3662760.474\n 71.8,-3813487.389, 3554291.446, 3662761.123\n 71.9,-3813487.218, 3554290.955, 3662761.774\n 72.0,-3813487.042, 3554290.467, 3662762.426\n 72.1,-3813486.860, 3554289.984, 3662763.080\n 72.2,-3813486.672, 3554289.505, 3662763.736\n 72.3,-3813486.480, 3554289.030, 3662764.393\n 72.4,-3813486.282, 3554288.559, 3662765.051\n 72.5,-3813486.079, 3554288.092, 3662765.711\n 72.6,-3813485.870, 3554287.630, 3662766.372\n 72.7,-3813485.656, 3554287.172, 3662767.035\n 72.8,-3813485.437, 3554286.719, 3662767.699\n 72.9,-3813485.213, 3554286.269, 3662768.364\n 73.0,-3813484.983, 3554285.825, 3662769.030\n 73.1,-3813484.748, 3554285.384, 3662769.697\n 73.2,-3813484.508, 3554284.948, 3662770.366\n 73.3,-3813484.263, 3554284.517, 3662771.035\n 73.4,-3813484.013, 3554284.090, 3662771.706\n 73.5,-3813483.757, 3554283.668, 3662772.377\n 73.6,-3813483.496, 3554283.250, 3662773.049\n 73.7,-3813483.230, 3554282.837, 3662773.722\n 73.8,-3813482.960, 3554282.428, 3662774.396\n 73.9,-3813482.684, 3554282.024, 3662775.071\n 74.0,-3813482.402, 3554281.625, 3662775.746\n 74.1,-3813482.116, 3554281.231, 3662776.422\n 74.2,-3813481.825, 3554280.841, 3662777.099\n 74.3,-3813481.529, 3554280.456, 3662777.776\n 74.4,-3813481.228, 3554280.076, 3662778.454\n 74.5,-3813480.922, 3554279.701, 3662779.132\n 74.6,-3813480.611, 3554279.331, 3662779.811\n 74.7,-3813480.295, 3554278.965, 3662780.490\n 74.8,-3813479.974, 3554278.605, 3662781.169\n 74.9,-3813479.648, 3554278.249, 3662781.849\n 75.0,-3813479.318, 3554277.898, 3662782.529\n 75.1,-3813478.982, 3554277.553, 3662783.209\n 75.2,-3813478.642, 3554277.212, 3662783.889\n 75.3,-3813478.297, 3554276.876, 3662784.569\n 75.4,-3813477.947, 3554276.546, 3662785.250\n 75.5,-3813477.593, 3554276.220, 3662785.930\n 75.6,-3813477.234, 3554275.900, 3662786.610\n 75.7,-3813476.870, 3554275.585, 3662787.290\n 75.8,-3813476.501, 3554275.275, 3662787.970\n 75.9,-3813476.128, 3554274.970, 3662788.650\n 76.0,-3813475.750, 3554274.670, 3662789.330\n 76.1,-3813475.368, 3554274.375, 3662790.009\n 76.2,-3813474.981, 3554274.086, 3662790.688\n 76.3,-3813474.590, 3554273.802, 3662791.367\n 76.4,-3813474.194, 3554273.523, 3662792.045\n 76.5,-3813473.793, 3554273.250, 3662792.723\n 76.6,-3813473.388, 3554272.982, 3662793.400\n 76.7,-3813472.979, 3554272.719, 3662794.077\n 76.8,-3813472.565, 3554272.461, 3662794.753\n 76.9,-3813472.147, 3554272.209, 3662795.428\n 77.0,-3813471.725, 3554271.962, 3662796.103\n 77.1,-3813471.298, 3554271.721, 3662796.776\n 77.2,-3813470.867, 3554271.485, 3662797.450\n 77.3,-3813470.432, 3554271.254, 3662798.122\n 77.4,-3813469.993, 3554271.029, 3662798.793\n 77.5,-3813469.549, 3554270.810, 3662799.464\n 77.6,-3813469.102, 3554270.596, 3662800.133\n 77.7,-3813468.650, 3554270.387, 3662800.801\n 77.8,-3813468.194, 3554270.184, 3662801.469\n 77.9,-3813467.734, 3554269.986, 3662802.135\n 78.0,-3813467.270, 3554269.794, 3662802.800\n 78.1,-3813466.802, 3554269.608, 3662803.464\n 78.2,-3813466.330, 3554269.427, 3662804.126\n 78.3,-3813465.854, 3554269.251, 3662804.787\n 78.4,-3813465.374, 3554269.081, 3662805.447\n 78.5,-3813464.890, 3554268.917, 3662806.106\n 78.6,-3813464.403, 3554268.759, 3662806.763\n 78.7,-3813463.912, 3554268.606, 3662807.418\n 78.8,-3813463.417, 3554268.458, 3662808.072\n 78.9,-3813462.918, 3554268.317, 3662808.725\n 79.0,-3813462.415, 3554268.181, 3662809.375\n 79.1,-3813461.909, 3554268.050, 3662810.024\n 79.2,-3813461.400, 3554267.926, 3662810.672\n 79.3,-3813460.886, 3554267.807, 3662811.317\n 79.4,-3813460.369, 3554267.693, 3662811.961\n 79.5,-3813459.849, 3554267.586, 3662812.603\n 79.6,-3813459.325, 3554267.484, 3662813.243\n 79.7,-3813458.798, 3554267.387, 3662813.881\n 79.8,-3813458.267, 3554267.297, 3662814.517\n 79.9,-3813457.733, 3554267.212, 3662815.151\n 80.0,-3813457.196, 3554267.133, 3662815.783\n 80.1,-3813456.655, 3554267.060, 3662816.413\n 80.2,-3813456.111, 3554266.992, 3662817.041\n 80.3,-3813455.564, 3554266.930, 3662817.666\n 80.4,-3813455.014, 3554266.874, 3662818.289\n 80.5,-3813454.460, 3554266.824, 3662818.910\n 80.6,-3813453.903, 3554266.779, 3662819.529\n 80.7,-3813453.344, 3554266.740, 3662820.145\n 80.8,-3813452.781, 3554266.707, 3662820.759\n 80.9,-3813452.215, 3554266.680, 3662821.370\n 81.0,-3813451.647, 3554266.658, 3662821.979\n 81.1,-3813451.075, 3554266.642, 3662822.585\n 81.2,-3813450.501, 3554266.632, 3662823.189\n 81.3,-3813449.924, 3554266.628, 3662823.790\n 81.4,-3813449.344, 3554266.630, 3662824.388\n 81.5,-3813448.761, 3554266.637, 3662824.984\n 81.6,-3813448.175, 3554266.650, 3662825.577\n 81.7,-3813447.587, 3554266.669, 3662826.167\n 81.8,-3813446.997, 3554266.694, 3662826.754\n 81.9,-3813446.403, 3554266.724, 3662827.339\n 82.0,-3813445.807, 3554266.760, 3662827.920\n 82.1,-3813445.209, 3554266.802, 3662828.498\n 82.2,-3813444.608, 3554266.850, 3662829.074\n 82.3,-3813444.005, 3554266.903, 3662829.646\n 82.4,-3813443.399, 3554266.962, 3662830.216\n 82.5,-3813442.791, 3554267.027, 3662830.782\n 82.6,-3813442.181, 3554267.098, 3662831.345\n 82.7,-3813441.568, 3554267.174, 3662831.905\n 82.8,-3813440.954, 3554267.256, 3662832.461\n 82.9,-3813440.337, 3554267.344, 3662833.015\n 83.0,-3813439.718, 3554267.437, 3662833.565\n 83.1,-3813439.097, 3554267.537, 3662834.111\n 83.2,-3813438.473, 3554267.642, 3662834.654\n 83.3,-3813437.848, 3554267.752, 3662835.194\n 83.4,-3813437.221, 3554267.869, 3662835.731\n 83.5,-3813436.592, 3554267.991, 3662836.264\n 83.6,-3813435.961, 3554268.118, 3662836.793\n 83.7,-3813435.329, 3554268.252, 3662837.319\n 83.8,-3813434.694, 3554268.391, 3662837.841\n 83.9,-3813434.058, 3554268.535, 3662838.359\n 84.0,-3813433.420, 3554268.686, 3662838.874\n 84.1,-3813432.781, 3554268.842, 3662839.385\n 84.2,-3813432.140, 3554269.003, 3662839.892\n 84.3,-3813431.497, 3554269.170, 3662840.396\n 84.4,-3813430.853, 3554269.343, 3662840.895\n 84.5,-3813430.207, 3554269.521, 3662841.391\n 84.6,-3813429.560, 3554269.705, 3662841.883\n 84.7,-3813428.912, 3554269.895, 3662842.371\n 84.8,-3813428.262, 3554270.090, 3662842.855\n 84.9,-3813427.611, 3554270.290, 3662843.335\n 85.0,-3813426.959, 3554270.496, 3662843.811\n 85.1,-3813426.305, 3554270.708, 3662844.283\n 85.2,-3813425.651, 3554270.925, 3662844.750\n 85.3,-3813424.995, 3554271.147, 3662845.214\n 85.4,-3813424.338, 3554271.375, 3662845.674\n 85.5,-3813423.680, 3554271.609, 3662846.129\n 85.6,-3813423.022, 3554271.848, 3662846.580\n 85.7,-3813422.362, 3554272.092, 3662847.027\n 85.8,-3813421.701, 3554272.341, 3662847.469\n 85.9,-3813421.040, 3554272.596, 3662847.907\n 86.0,-3813420.378, 3554272.857, 3662848.341\n 86.1,-3813419.715, 3554273.122, 3662848.771\n 86.2,-3813419.051, 3554273.393, 3662849.196\n 86.3,-3813418.387, 3554273.670, 3662849.616\n 86.4,-3813417.722, 3554273.951, 3662850.032\n 86.5,-3813417.057, 3554274.238, 3662850.444\n 86.6,-3813416.391, 3554274.530, 3662850.851\n 86.7,-3813415.725, 3554274.828, 3662851.254\n 86.8,-3813415.058, 3554275.130, 3662851.652\n 86.9,-3813414.391, 3554275.438, 3662852.045\n 87.0,-3813413.723, 3554275.751, 3662852.434\n 87.1,-3813413.056, 3554276.068, 3662852.818\n 87.2,-3813412.388, 3554276.392, 3662853.197\n 87.3,-3813411.720, 3554276.720, 3662853.572\n 87.4,-3813411.051, 3554277.053, 3662853.942\n 87.5,-3813410.383, 3554277.391, 3662854.307\n 87.6,-3813409.715, 3554277.735, 3662854.667\n 87.7,-3813409.046, 3554278.083, 3662855.023\n 87.8,-3813408.378, 3554278.436, 3662855.373\n 87.9,-3813407.710, 3554278.794, 3662855.719\n 88.0,-3813407.041, 3554279.158, 3662856.060\n 88.1,-3813406.374, 3554279.526, 3662856.396\n 88.2,-3813405.706, 3554279.898, 3662856.727\n 88.3,-3813405.038, 3554280.276, 3662857.053\n 88.4,-3813404.371, 3554280.659, 3662857.374\n 88.5,-3813403.705, 3554281.046, 3662857.690\n 88.6,-3813403.038, 3554281.438, 3662858.001\n 88.7,-3813402.373, 3554281.835, 3662858.307\n 88.8,-3813401.707, 3554282.237, 3662858.608\n 88.9,-3813401.043, 3554282.643, 3662858.904\n 89.0,-3813400.378, 3554283.054, 3662859.194\n 89.1,-3813399.715, 3554283.470, 3662859.480\n 89.2,-3813399.052, 3554283.890, 3662859.760\n 89.3,-3813398.390, 3554284.315, 3662860.036\n 89.4,-3813397.729, 3554284.744, 3662860.306\n 89.5,-3813397.069, 3554285.178, 3662860.571\n 89.6,-3813396.409, 3554285.616, 3662860.830\n 89.7,-3813395.750, 3554286.059, 3662861.084\n 89.8,-3813395.093, 3554286.506, 3662861.333\n 89.9,-3813394.436, 3554286.957, 3662861.577\n 90.0,-3813393.781, 3554287.413, 3662861.816\n 90.1,-3813393.126, 3554287.874, 3662862.049\n 90.2,-3813392.473, 3554288.338, 3662862.277\n 90.3,-3813391.821, 3554288.807, 3662862.499\n 90.4,-3813391.170, 3554289.280, 3662862.716\n 90.5,-3813390.521, 3554289.757, 3662862.928\n 90.6,-3813389.872, 3554290.238, 3662863.134\n 90.7,-3813389.226, 3554290.724, 3662863.335\n 90.8,-3813388.580, 3554291.213, 3662863.531\n 90.9,-3813387.936, 3554291.707, 3662863.721\n 91.0,-3813387.294, 3554292.205, 3662863.906\n 91.1,-3813386.653, 3554292.706, 3662864.085\n 91.2,-3813386.014, 3554293.212, 3662864.258\n 91.3,-3813385.376, 3554293.722, 3662864.427\n 91.4,-3813384.740, 3554294.235, 3662864.589\n 91.5,-3813384.106, 3554294.752, 3662864.746\n 91.6,-3813383.474, 3554295.274, 3662864.898\n 91.7,-3813382.843, 3554295.798, 3662865.044\n 91.8,-3813382.215, 3554296.327, 3662865.185\n 91.9,-3813381.588, 3554296.859, 3662865.320\n 92.0,-3813380.963, 3554297.395, 3662865.449\n 92.1,-3813380.340, 3554297.935, 3662865.573\n 92.2,-3813379.720, 3554298.478, 3662865.692\n 92.3,-3813379.101, 3554299.025, 3662865.804\n 92.4,-3813378.484, 3554299.575, 3662865.911\n 92.5,-3813377.870, 3554300.129, 3662866.013\n 92.6,-3813377.258, 3554300.686, 3662866.109\n 92.7,-3813376.648, 3554301.247, 3662866.199\n 92.8,-3813376.040, 3554301.811, 3662866.284\n 92.9,-3813375.435, 3554302.378, 3662866.363\n 93.0,-3813374.832, 3554302.949, 3662866.436\n 93.1,-3813374.232, 3554303.523, 3662866.504\n 93.2,-3813373.634, 3554304.100, 3662866.566\n 93.3,-3813373.038, 3554304.680, 3662866.623\n 93.4,-3813372.446, 3554305.264, 3662866.674\n 93.5,-3813371.855, 3554305.850, 3662866.719\n 93.6,-3813371.268, 3554306.439, 3662866.759\n 93.7,-3813370.683, 3554307.032, 3662866.792\n 93.8,-3813370.100, 3554307.627, 3662866.821\n 93.9,-3813369.521, 3554308.226, 3662866.843\n 94.0,-3813368.944, 3554308.827, 3662866.860\n 94.1,-3813368.370, 3554309.431, 3662866.871\n 94.2,-3813367.799, 3554310.038, 3662866.877\n 94.3,-3813367.231, 3554310.648, 3662866.877\n 94.4,-3813366.666, 3554311.260, 3662866.871\n 94.5,-3813366.104, 3554311.875, 3662866.859\n 94.6,-3813365.544, 3554312.493, 3662866.842\n 94.7,-3813364.988, 3554313.113, 3662866.819\n 94.8,-3813364.435, 3554313.736, 3662866.791\n 94.9,-3813363.886, 3554314.361, 3662866.757\n 95.0,-3813363.339, 3554314.989, 3662866.717\n 95.1,-3813362.796, 3554315.619, 3662866.672\n 95.2,-3813362.255, 3554316.252, 3662866.621\n 95.3,-3813361.719, 3554316.886, 3662866.564\n 95.4,-3813361.185, 3554317.524, 3662866.501\n 95.5,-3813360.655, 3554318.163, 3662866.433\n 95.6,-3813360.128, 3554318.804, 3662866.360\n 95.7,-3813359.605, 3554319.448, 3662866.280\n 95.8,-3813359.085, 3554320.094, 3662866.195\n 95.9,-3813358.569, 3554320.742, 3662866.105\n 96.0,-3813358.056, 3554321.392, 3662866.009\n 96.1,-3813357.547, 3554322.043, 3662865.907\n 96.2,-3813357.042, 3554322.697, 3662865.799\n 96.3,-3813356.540, 3554323.353, 3662865.686\n 96.4,-3813356.042, 3554324.010, 3662865.568\n 96.5,-3813355.547, 3554324.670, 3662865.444\n 96.6,-3813355.057, 3554325.331, 3662865.314\n 96.7,-3813354.570, 3554325.993, 3662865.179\n 96.8,-3813354.087, 3554326.658, 3662865.038\n 96.9,-3813353.608, 3554327.323, 3662864.892\n 97.0,-3813353.132, 3554327.991, 3662864.740\n 97.1,-3813352.661, 3554328.660, 3662864.582\n 97.2,-3813352.194, 3554329.330, 3662864.419\n 97.3,-3813351.730, 3554330.002, 3662864.251\n 97.4,-3813351.271, 3554330.675, 3662864.077\n 97.5,-3813350.816, 3554331.350, 3662863.897\n 97.6,-3813350.365, 3554332.026, 3662863.713\n 97.7,-3813349.918, 3554332.703, 3662863.522\n 97.8,-3813349.475, 3554333.381, 3662863.327\n 97.9,-3813349.036, 3554334.060, 3662863.125\n 98.0,-3813348.602, 3554334.741, 3662862.919\n 98.1,-3813348.171, 3554335.422, 3662862.707\n 98.2,-3813347.746, 3554336.105, 3662862.489\n 98.3,-3813347.324, 3554336.788, 3662862.267\n 98.4,-3813346.907, 3554337.473, 3662862.039\n 98.5,-3813346.494, 3554338.158, 3662861.805\n 98.6,-3813346.085, 3554338.844, 3662861.567\n 98.7,-3813345.681, 3554339.530, 3662861.323\n 98.8,-3813345.281, 3554340.218, 3662861.073\n 98.9,-3813344.886, 3554340.906, 3662860.819\n 99.0,-3813344.496, 3554341.595, 3662860.559\n 99.1,-3813344.109, 3554342.284, 3662860.294\n 99.2,-3813343.728, 3554342.974, 3662860.024\n 99.3,-3813343.351, 3554343.664, 3662859.748\n 99.4,-3813342.978, 3554344.355, 3662859.467\n 99.5,-3813342.611, 3554345.046, 3662859.182\n 99.6,-3813342.248, 3554345.737, 3662858.891\n 99.7,-3813341.889, 3554346.429, 3662858.595\n 99.8,-3813341.536, 3554347.120, 3662858.294\n 99.9,-3813341.187, 3554347.813, 3662857.987\n100.0,-3813340.842, 3554348.505, 3662857.676\n100.1,-3813340.503, 3554349.197, 3662857.360\n100.2,-3813340.168, 3554349.889, 3662857.039\n100.3,-3813339.839, 3554350.582, 3662856.712\n100.4,-3813339.514, 3554351.274, 3662856.381\n100.5,-3813339.194, 3554351.966, 3662856.045\n100.6,-3813338.879, 3554352.658, 3662855.704\n100.7,-3813338.569, 3554353.350, 3662855.358\n100.8,-3813338.263, 3554354.041, 3662855.007\n100.9,-3813337.963, 3554354.732, 3662854.651\n101.0,-3813337.668, 3554355.423, 3662854.291\n101.1,-3813337.377, 3554356.114, 3662853.925\n101.2,-3813337.092, 3554356.804, 3662853.555\n101.3,-3813336.812, 3554357.493, 3662853.180\n101.4,-3813336.537, 3554358.182, 3662852.801\n101.5,-3813336.267, 3554358.870, 3662852.417\n101.6,-3813336.002, 3554359.558, 3662852.028\n101.7,-3813335.742, 3554360.245, 3662851.634\n101.8,-3813335.487, 3554360.931, 3662851.236\n101.9,-3813335.238, 3554361.617, 3662850.833\n102.0,-3813334.993, 3554362.302, 3662850.426\n102.1,-3813334.754, 3554362.986, 3662850.014\n102.2,-3813334.520, 3554363.669, 3662849.598\n102.3,-3813334.292, 3554364.350, 3662849.177\n102.4,-3813334.068, 3554365.031, 3662848.752\n102.5,-3813333.850, 3554365.711, 3662848.322\n102.6,-3813333.637, 3554366.390, 3662847.888\n102.7,-3813333.429, 3554367.068, 3662847.450\n102.8,-3813333.227, 3554367.744, 3662847.007\n102.9,-3813333.030, 3554368.419, 3662846.560\n103.0,-3813332.838, 3554369.093, 3662846.109\n103.1,-3813332.652, 3554369.765, 3662845.653\n103.2,-3813332.471, 3554370.437, 3662845.194\n103.3,-3813332.295, 3554371.106, 3662844.730\n103.4,-3813332.125, 3554371.774, 3662844.262\n103.5,-3813331.960, 3554372.441, 3662843.790\n103.6,-3813331.800, 3554373.106, 3662843.314\n103.7,-3813331.646, 3554373.770, 3662842.833\n103.8,-3813331.498, 3554374.431, 3662842.349\n103.9,-3813331.355, 3554375.091, 3662841.861\n104.0,-3813331.217, 3554375.750, 3662841.369\n104.1,-3813331.084, 3554376.406, 3662840.873\n104.2,-3813330.958, 3554377.061, 3662840.373\n104.3,-3813330.836, 3554377.713, 3662839.870\n104.4,-3813330.720, 3554378.364, 3662839.362\n104.5,-3813330.610, 3554379.013, 3662838.851\n104.6,-3813330.505, 3554379.660, 3662838.336\n104.7,-3813330.406, 3554380.304, 3662837.818\n104.8,-3813330.312, 3554380.947, 3662837.295\n104.9,-3813330.223, 3554381.587, 3662836.769\n105.0,-3813330.141, 3554382.226, 3662836.240\n105.1,-3813330.063, 3554382.861, 3662835.707\n105.2,-3813329.992, 3554383.495, 3662835.170\n105.3,-3813329.925, 3554384.126, 3662834.630\n105.4,-3813329.865, 3554384.755, 3662834.087\n105.5,-3813329.809, 3554385.382, 3662833.540\n105.6,-3813329.760, 3554386.006, 3662832.990\n105.7,-3813329.716, 3554386.627, 3662832.437\n105.8,-3813329.677, 3554387.246, 3662831.880\n105.9,-3813329.644, 3554387.862, 3662831.320\n106.0,-3813329.617, 3554388.476, 3662830.757\n106.1,-3813329.595, 3554389.087, 3662830.190\n106.2,-3813329.579, 3554389.695, 3662829.621\n106.3,-3813329.569, 3554390.300, 3662829.048\n106.4,-3813329.563, 3554390.903, 3662828.473\n106.5,-3813329.564, 3554391.503, 3662827.894\n106.6,-3813329.570, 3554392.099, 3662827.313\n106.7,-3813329.582, 3554392.693, 3662826.728\n106.8,-3813329.599, 3554393.284, 3662826.141\n106.9,-3813329.622, 3554393.872, 3662825.551\n107.0,-3813329.650, 3554394.457, 3662824.958\n107.1,-3813329.684, 3554395.039, 3662824.362\n107.2,-3813329.723, 3554395.617, 3662823.763\n107.3,-3813329.768, 3554396.192, 3662823.162\n107.4,-3813329.819, 3554396.765, 3662822.558\n107.5,-3813329.875, 3554397.333, 3662821.952\n107.6,-3813329.937, 3554397.899, 3662821.343\n107.7,-3813330.004, 3554398.461, 3662820.732\n107.8,-3813330.077, 3554399.020, 3662820.118\n107.9,-3813330.155, 3554399.575, 3662819.502\n108.0,-3813330.239, 3554400.127, 3662818.883\n108.1,-3813330.328, 3554400.676, 3662818.262\n108.2,-3813330.423, 3554401.221, 3662817.638\n108.3,-3813330.523, 3554401.762, 3662817.013\n108.4,-3813330.629, 3554402.300, 3662816.385\n108.5,-3813330.741, 3554402.834, 3662815.755\n108.6,-3813330.858, 3554403.364, 3662815.123\n108.7,-3813330.980, 3554403.891, 3662814.489\n108.8,-3813331.108, 3554404.414, 3662813.853\n108.9,-3813331.241, 3554404.933, 3662813.215\n109.0,-3813331.380, 3554405.448, 3662812.575\n109.1,-3813331.524, 3554405.959, 3662811.933\n109.2,-3813331.674, 3554406.467, 3662811.289\n109.3,-3813331.829, 3554406.970, 3662810.643\n109.4,-3813331.989, 3554407.470, 3662809.996\n109.5,-3813332.155, 3554407.965, 3662809.346\n109.6,-3813332.326, 3554408.457, 3662808.696\n109.7,-3813332.503, 3554408.944, 3662808.043\n109.8,-3813332.685, 3554409.427, 3662807.389\n109.9,-3813332.872, 3554409.907, 3662806.734\n110.0,-3813333.065, 3554410.381, 3662806.076\n110.1,-3813333.263, 3554410.852, 3662805.418\n110.2,-3813333.466, 3554411.319, 3662804.758\n110.3,-3813333.675, 3554411.781, 3662804.097\n110.4,-3813333.889, 3554412.239, 3662803.434\n110.5,-3813334.108, 3554412.692, 3662802.770\n110.6,-3813334.332, 3554413.142, 3662802.105\n110.7,-3813334.562, 3554413.586, 3662801.439\n110.8,-3813334.797, 3554414.027, 3662800.772\n110.9,-3813335.037, 3554414.463, 3662800.103\n111.0,-3813335.282, 3554414.894, 3662799.434\n111.1,-3813335.533, 3554415.321, 3662798.763\n111.2,-3813335.788, 3554415.743, 3662798.092\n111.3,-3813336.049, 3554416.161, 3662797.420\n111.4,-3813336.315, 3554416.574, 3662796.747\n111.5,-3813336.586, 3554416.982, 3662796.073\n111.6,-3813336.862, 3554417.386, 3662795.398\n111.7,-3813337.143, 3554417.785, 3662794.723\n111.8,-3813337.429, 3554418.180, 3662794.047\n111.9,-3813337.720, 3554418.569, 3662793.370\n112.0,-3813338.016, 3554418.954, 3662792.693\n112.1,-3813338.318, 3554419.334, 3662792.015\n112.2,-3813338.624, 3554419.709, 3662791.337\n112.3,-3813338.935, 3554420.080, 3662790.658\n112.4,-3813339.251, 3554420.445, 3662789.979\n112.5,-3813339.572, 3554420.805, 3662789.300\n112.6,-3813339.897, 3554421.161, 3662788.620\n112.7,-3813340.228, 3554421.512, 3662787.940\n112.8,-3813340.563, 3554421.857, 3662787.260\n112.9,-3813340.904, 3554422.198, 3662786.580\n113.0,-3813341.249, 3554422.533, 3662785.900\n113.1,-3813341.599, 3554422.864, 3662785.219\n113.2,-3813341.953, 3554423.189, 3662784.539\n113.3,-3813342.312, 3554423.510, 3662783.859\n113.4,-3813342.676, 3554423.825, 3662783.179\n113.5,-3813343.045, 3554424.135, 3662782.499\n113.6,-3813343.418, 3554424.440, 3662781.819\n113.7,-3813343.796, 3554424.740, 3662781.139\n113.8,-3813344.178, 3554425.034, 3662780.460\n113.9,-3813344.565, 3554425.323, 3662779.781\n114.0,-3813344.957, 3554425.607, 3662779.102\n114.1,-3813345.353, 3554425.886, 3662778.424\n114.2,-3813345.753, 3554426.160, 3662777.746\n114.3,-3813346.158, 3554426.428, 3662777.069\n114.4,-3813346.567, 3554426.691, 3662776.392\n114.5,-3813346.981, 3554426.948, 3662775.716\n114.6,-3813347.399, 3554427.200, 3662775.041\n114.7,-3813347.822, 3554427.447, 3662774.366\n114.8,-3813348.248, 3554427.688, 3662773.693\n114.9,-3813348.679, 3554427.924, 3662773.019\n115.0,-3813349.114, 3554428.155, 3662772.347\n115.1,-3813349.554, 3554428.380, 3662771.676\n115.2,-3813349.997, 3554428.599, 3662771.005\n115.3,-3813350.445, 3554428.813, 3662770.336\n115.4,-3813350.897, 3554429.022, 3662769.668\n115.5,-3813351.353, 3554429.225, 3662769.000\n115.6,-3813351.813, 3554429.422, 3662768.334\n115.7,-3813352.277, 3554429.614, 3662767.669\n115.8,-3813352.745, 3554429.801, 3662767.005\n115.9,-3813353.217, 3554429.982, 3662766.343\n116.0,-3813353.693, 3554430.157, 3662765.682\n116.1,-3813354.173, 3554430.327, 3662765.022\n116.2,-3813354.657, 3554430.491, 3662764.363\n116.3,-3813355.144, 3554430.650, 3662763.706\n116.4,-3813355.636, 3554430.803, 3662763.051\n116.5,-3813356.131, 3554430.950, 3662762.397\n116.6,-3813356.629, 3554431.092, 3662761.745\n116.7,-3813357.132, 3554431.227, 3662761.094\n116.8,-3813357.638, 3554431.358, 3662760.445\n116.9,-3813358.148, 3554431.482, 3662759.798\n117.0,-3813358.661, 3554431.601, 3662759.152\n117.1,-3813359.178, 3554431.715, 3662758.508\n117.2,-3813359.698, 3554431.822, 3662757.866\n117.3,-3813360.222, 3554431.924, 3662757.226\n117.4,-3813360.750, 3554432.020, 3662756.588\n117.5,-3813361.280, 3554432.111, 3662755.952\n117.6,-3813361.814, 3554432.196, 3662755.318\n117.7,-3813362.352, 3554432.275, 3662754.686\n117.8,-3813362.893, 3554432.348, 3662754.056\n117.9,-3813363.437, 3554432.416, 3662753.429\n118.0,-3813363.984, 3554432.477, 3662752.803\n118.1,-3813364.534, 3554432.533, 3662752.180\n118.2,-3813365.088, 3554432.584, 3662751.559\n118.3,-3813365.644, 3554432.628, 3662750.941\n118.4,-3813366.204, 3554432.667, 3662750.324\n118.5,-3813366.767, 3554432.700, 3662749.711\n118.6,-3813367.332, 3554432.727, 3662749.099\n118.7,-3813367.901, 3554432.749, 3662748.491\n118.8,-3813368.473, 3554432.765, 3662747.884\n118.9,-3813369.047, 3554432.775, 3662747.281\n119.0,-3813369.624, 3554432.779, 3662746.680\n119.1,-3813370.204, 3554432.777, 3662746.081\n119.2,-3813370.787, 3554432.770, 3662745.486\n119.3,-3813371.373, 3554432.757, 3662744.893\n119.4,-3813371.961, 3554432.738, 3662744.303\n119.5,-3813372.552, 3554432.713, 3662743.716\n119.6,-3813373.145, 3554432.683, 3662743.131\n119.7,-3813373.741, 3554432.647, 3662742.550\n119.8,-3813374.339, 3554432.605, 3662741.971\n119.9,-3813374.940, 3554432.557, 3662741.396\n120.0,-3813375.543, 3554432.504, 3662740.824\n120.1,-3813376.149, 3554432.444, 3662740.254\n120.2,-3813376.757, 3554432.379, 3662739.688\n120.3,-3813377.367, 3554432.309, 3662739.125\n120.4,-3813377.980, 3554432.232, 3662738.565\n120.5,-3813378.595, 3554432.150, 3662738.009\n120.6,-3813379.212, 3554432.062, 3662737.455\n120.7,-3813379.831, 3554431.969, 3662736.905\n120.8,-3813380.452, 3554431.869, 3662736.359\n120.9,-3813381.075, 3554431.764, 3662735.816\n121.0,-3813381.700, 3554431.654, 3662735.276\n121.1,-3813382.327, 3554431.537, 3662734.740\n121.2,-3813382.956, 3554431.415, 3662734.207\n121.3,-3813383.587, 3554431.287, 3662733.677\n121.4,-3813384.220, 3554431.154, 3662733.152\n121.5,-3813384.854, 3554431.015, 3662732.630\n121.6,-3813385.490, 3554430.870, 3662732.111\n121.7,-3813386.128, 3554430.720, 3662731.597\n121.8,-3813386.768, 3554430.564, 3662731.086\n121.9,-3813387.409, 3554430.402, 3662730.578\n122.0,-3813388.052, 3554430.235, 3662730.075\n122.1,-3813388.696, 3554430.062, 3662729.575\n122.2,-3813389.341, 3554429.884, 3662729.080\n122.3,-3813389.988, 3554429.700, 3662728.588\n122.4,-3813390.637, 3554429.510, 3662728.100\n122.5,-3813391.287, 3554429.315, 3662727.616\n122.6,-3813391.938, 3554429.115, 3662727.136\n122.7,-3813392.590, 3554428.909, 3662726.660\n122.8,-3813393.243, 3554428.697, 3662726.188\n122.9,-3813393.898, 3554428.480, 3662725.720\n123.0,-3813394.554, 3554428.257, 3662725.257\n123.1,-3813395.211, 3554428.029, 3662724.797\n123.2,-3813395.868, 3554427.796, 3662724.342\n123.3,-3813396.527, 3554427.557, 3662723.891\n123.4,-3813397.187, 3554427.313, 3662723.444\n123.5,-3813397.847, 3554427.063, 3662723.002\n123.6,-3813398.509, 3554426.808, 3662722.564\n123.7,-3813399.171, 3554426.548, 3662722.130\n123.8,-3813399.834, 3554426.282, 3662721.700\n123.9,-3813400.497, 3554426.011, 3662721.275\n124.0,-3813401.162, 3554425.735, 3662720.855\n124.1,-3813401.826, 3554425.453, 3662720.439\n124.2,-3813402.492, 3554425.166, 3662720.027\n124.3,-3813403.158, 3554424.874, 3662719.620\n124.4,-3813403.824, 3554424.577, 3662719.218\n124.5,-3813404.491, 3554424.274, 3662718.820\n124.6,-3813405.158, 3554423.967, 3662718.426\n124.7,-3813405.825, 3554423.654, 3662718.038\n124.8,-3813406.493, 3554423.336, 3662717.654\n124.9,-3813407.161, 3554423.013, 3662717.274\n125.0,-3813407.829, 3554422.684, 3662716.900\n125.1,-3813408.497, 3554422.351, 3662716.530\n125.2,-3813409.166, 3554422.013, 3662716.165\n125.3,-3813409.834, 3554421.669, 3662715.805\n125.4,-3813410.503, 3554421.321, 3662715.449\n125.5,-3813411.171, 3554420.968, 3662715.099\n125.6,-3813411.839, 3554420.609, 3662714.753\n125.7,-3813412.507, 3554420.246, 3662714.412\n125.8,-3813413.175, 3554419.878, 3662714.076\n125.9,-3813413.843, 3554419.505, 3662713.745\n126.0,-3813414.510, 3554419.127, 3662713.419\n126.1,-3813415.177, 3554418.745, 3662713.098\n126.2,-3813415.844, 3554418.357, 3662712.782\n126.3,-3813416.510, 3554417.965, 3662712.471\n126.4,-3813417.176, 3554417.568, 3662712.165\n126.5,-3813417.841, 3554417.166, 3662711.864\n126.6,-3813418.506, 3554416.760, 3662711.569\n126.7,-3813419.170, 3554416.349, 3662711.278\n126.8,-3813419.834, 3554415.934, 3662710.992\n126.9,-3813420.496, 3554415.513, 3662710.712\n127.0,-3813421.158, 3554415.089, 3662710.437\n127.1,-3813421.820, 3554414.659, 3662710.167\n127.2,-3813422.480, 3554414.225, 3662709.902\n127.3,-3813423.140, 3554413.787, 3662709.643\n127.4,-3813423.798, 3554413.344, 3662709.388\n127.5,-3813424.456, 3554412.897, 3662709.139\n127.6,-3813425.112, 3554412.446, 3662708.896\n127.7,-3813425.768, 3554411.990, 3662708.657\n127.8,-3813426.422, 3554411.529, 3662708.424\n127.9,-3813427.076, 3554411.065, 3662708.196\n128.0,-3813427.728, 3554410.596, 3662707.974\n128.1,-3813428.378, 3554410.123, 3662707.757\n128.2,-3813429.028, 3554409.646, 3662707.545\n128.3,-3813429.676, 3554409.164, 3662707.339\n128.4,-3813430.323, 3554408.679, 3662707.138\n128.5,-3813430.968, 3554408.189, 3662706.942\n128.6,-3813431.612, 3554407.695, 3662706.752\n128.7,-3813432.255, 3554407.198, 3662706.568\n128.8,-3813432.895, 3554406.696, 3662706.389\n128.9,-3813433.535, 3554406.190, 3662706.215\n129.0,-3813434.172, 3554405.681, 3662706.047\n129.1,-3813434.808, 3554405.167, 3662705.884\n129.2,-3813435.442, 3554404.650, 3662705.727\n129.3,-3813436.075, 3554404.129, 3662705.576\n129.4,-3813436.705, 3554403.604, 3662705.429\n129.5,-3813437.334, 3554403.075, 3662705.289\n129.6,-3813437.960, 3554402.543, 3662705.154\n129.7,-3813438.585, 3554402.007, 3662705.024\n129.8,-3813439.208, 3554401.467, 3662704.901\n129.9,-3813439.829, 3554400.924, 3662704.782\n130.0,-3813440.447, 3554400.377, 3662704.670\n130.1,-3813441.064, 3554399.827, 3662704.563\n130.2,-3813441.678, 3554399.273, 3662704.461\n130.3,-3813442.290, 3554398.716, 3662704.365\n130.4,-3813442.900, 3554398.155, 3662704.275\n130.5,-3813443.508, 3554397.591, 3662704.190\n130.6,-3813444.113, 3554397.024, 3662704.111\n130.7,-3813444.716, 3554396.453, 3662704.038\n130.8,-3813445.316, 3554395.879, 3662703.970\n130.9,-3813445.914, 3554395.302, 3662703.908\n131.0,-3813446.510, 3554394.722, 3662703.852\n131.1,-3813447.103, 3554394.138, 3662703.801\n131.2,-3813447.693, 3554393.552, 3662703.756\n131.3,-3813448.280, 3554392.962, 3662703.716\n131.4,-3813448.865, 3554392.370, 3662703.682\n131.5,-3813449.448, 3554391.774, 3662703.654\n131.6,-3813450.027, 3554391.176, 3662703.632\n131.7,-3813450.604, 3554390.574, 3662703.615\n131.8,-3813451.178, 3554389.970, 3662703.604\n131.9,-3813451.749, 3554389.363, 3662703.598\n132.0,-3813452.317, 3554388.754, 3662703.598\n132.1,-3813452.882, 3554388.141, 3662703.604\n132.2,-3813453.444, 3554387.526, 3662703.616\n132.3,-3813454.003, 3554386.909, 3662703.633\n132.4,-3813454.559, 3554386.288, 3662703.656\n132.5,-3813455.112, 3554385.666, 3662703.684\n132.6,-3813455.662, 3554385.040, 3662703.718\n132.7,-3813456.209, 3554384.412, 3662703.758\n132.8,-3813456.752, 3554383.782, 3662703.804\n132.9,-3813457.292, 3554383.150, 3662703.855\n133.0,-3813457.829, 3554382.515, 3662703.912\n133.1,-3813458.362, 3554381.878, 3662703.974\n133.2,-3813458.893, 3554381.238, 3662704.042\n133.3,-3813459.419, 3554380.597, 3662704.116\n133.4,-3813459.942, 3554379.953, 3662704.195\n133.5,-3813460.462, 3554379.307, 3662704.280\n133.6,-3813460.978, 3554378.659, 3662704.371\n133.7,-3813461.491, 3554378.010, 3662704.467\n133.8,-3813462.000, 3554377.358, 3662704.569\n133.9,-3813462.506, 3554376.704, 3662704.676\n134.0,-3813463.007, 3554376.048, 3662704.790\n134.1,-3813463.506, 3554375.391, 3662704.908\n134.2,-3813464.000, 3554374.732, 3662705.032\n134.3,-3813464.491, 3554374.071, 3662705.162\n134.4,-3813464.977, 3554373.408, 3662705.297\n134.5,-3813465.460, 3554372.744, 3662705.438\n134.6,-3813465.939, 3554372.078, 3662705.585\n134.7,-3813466.415, 3554371.410, 3662705.737\n134.8,-3813466.886, 3554370.741, 3662705.894\n134.9,-3813467.353, 3554370.071, 3662706.057\n135.0,-3813467.816, 3554369.399, 3662706.226\n135.1,-3813468.276, 3554368.726, 3662706.400\n135.2,-3813468.731, 3554368.051, 3662706.579\n135.3,-3813469.182, 3554367.375, 3662706.764\n135.4,-3813469.629, 3554366.698, 3662706.954\n135.5,-3813470.072, 3554366.020, 3662707.150\n135.6,-3813470.511, 3554365.341, 3662707.351\n135.7,-3813470.945, 3554364.660, 3662707.558\n135.8,-3813471.375, 3554363.979, 3662707.770\n135.9,-3813471.801, 3554363.296, 3662707.987\n136.0,-3813472.223, 3554362.613, 3662708.210\n136.1,-3813472.640, 3554361.928, 3662708.438\n136.2,-3813473.053, 3554361.243, 3662708.672\n136.3,-3813473.461, 3554360.557, 3662708.911\n136.4,-3813473.865, 3554359.870, 3662709.155\n136.5,-3813474.265, 3554359.183, 3662709.404\n136.6,-3813474.660, 3554358.495, 3662709.659\n136.7,-3813475.051, 3554357.806, 3662709.918\n136.8,-3813475.437, 3554357.117, 3662710.184\n136.9,-3813475.818, 3554356.427, 3662710.454\n137.0,-3813476.195, 3554355.737, 3662710.729\n137.1,-3813476.568, 3554355.046, 3662711.010\n137.2,-3813476.935, 3554354.355, 3662711.296\n137.3,-3813477.298, 3554353.664, 3662711.587\n137.4,-3813477.657, 3554352.972, 3662711.883\n137.5,-3813478.010, 3554352.280, 3662712.184\n137.6,-3813478.359, 3554351.588, 3662712.490\n137.7,-3813478.703, 3554350.896, 3662712.802\n137.8,-3813479.043, 3554350.204, 3662713.118\n137.9,-3813479.377, 3554349.512, 3662713.439\n138.0,-3813479.707, 3554348.819, 3662713.766\n138.1,-3813480.032, 3554348.127, 3662714.097\n138.2,-3813480.352, 3554347.435, 3662714.433\n138.3,-3813480.667, 3554346.743, 3662714.774\n138.4,-3813480.977, 3554346.051, 3662715.120\n138.5,-3813481.282, 3554345.360, 3662715.471\n138.6,-3813481.582, 3554344.669, 3662715.827\n138.7,-3813481.878, 3554343.978, 3662716.188\n138.8,-3813482.168, 3554343.287, 3662716.553\n138.9,-3813482.453, 3554342.597, 3662716.923\n139.0,-3813482.733, 3554341.908, 3662717.298\n139.1,-3813483.008, 3554341.219, 3662717.678\n139.2,-3813483.278, 3554340.530, 3662718.062\n139.3,-3813483.543, 3554339.843, 3662718.451\n139.4,-3813483.803, 3554339.156, 3662718.844\n139.5,-3813484.058, 3554338.469, 3662719.243\n139.6,-3813484.307, 3554337.784, 3662719.645\n139.7,-3813484.552, 3554337.099, 3662720.053\n139.8,-3813484.791, 3554336.415, 3662720.465\n139.9,-3813485.025, 3554335.732, 3662720.881\n140.0,-3813485.253, 3554335.050, 3662721.302\n140.1,-3813485.477, 3554334.370, 3662721.727\n140.2,-3813485.695, 3554333.690, 3662722.157\n140.3,-3813485.908, 3554333.011, 3662722.591\n140.4,-3813486.115, 3554332.333, 3662723.029\n140.5,-3813486.318, 3554331.657, 3662723.472\n140.6,-3813486.515, 3554330.982, 3662723.919\n140.7,-3813486.706, 3554330.308, 3662724.370\n140.8,-3813486.893, 3554329.635, 3662724.826\n140.9,-3813487.074, 3554328.964, 3662725.285\n141.0,-3813487.249, 3554328.295, 3662725.749\n141.1,-3813487.420, 3554327.627, 3662726.217\n141.2,-3813487.584, 3554326.960, 3662726.689\n141.3,-3813487.744, 3554326.295, 3662727.166\n141.4,-3813487.898, 3554325.631, 3662727.646\n141.5,-3813488.046, 3554324.970, 3662728.130\n141.6,-3813488.190, 3554324.310, 3662728.618\n141.7,-3813488.327, 3554323.651, 3662729.110\n141.8,-3813488.460, 3554322.995, 3662729.606\n141.9,-3813488.586, 3554322.340, 3662730.106\n142.0,-3813488.708, 3554321.688, 3662730.610\n142.1,-3813488.823, 3554321.037, 3662731.117\n142.2,-3813488.934, 3554320.388, 3662731.628\n142.3,-3813489.039, 3554319.741, 3662732.143\n142.4,-3813489.138, 3554319.097, 3662732.662\n142.5,-3813489.232, 3554318.454, 3662733.184\n142.6,-3813489.320, 3554317.814, 3662733.710\n142.7,-3813489.403, 3554317.176, 3662734.240\n142.8,-3813489.480, 3554316.540, 3662734.773\n142.9,-3813489.552, 3554315.906, 3662735.309\n143.0,-3813489.618, 3554315.275, 3662735.849\n143.1,-3813489.679, 3554314.646, 3662736.393\n143.2,-3813489.734, 3554314.020, 3662736.940\n143.3,-3813489.783, 3554313.396, 3662737.490\n143.4,-3813489.827, 3554312.774, 3662738.043\n143.5,-3813489.866, 3554312.156, 3662738.600\n143.6,-3813489.899, 3554311.539, 3662739.160\n143.7,-3813489.926, 3554310.926, 3662739.723\n143.8,-3813489.948, 3554310.315, 3662740.290\n143.9,-3813489.964, 3554309.707, 3662740.859\n144.0,-3813489.974, 3554309.101, 3662741.432\n144.1,-3813489.979, 3554308.499, 3662742.007\n144.2,-3813489.979, 3554307.899, 3662742.586\n144.3,-3813489.973, 3554307.302, 3662743.168\n144.4,-3813489.961, 3554306.708, 3662743.752\n144.5,-3813489.944, 3554306.118, 3662744.339\n144.6,-3813489.921, 3554305.530, 3662744.930\n144.7,-3813489.893, 3554304.945, 3662745.523\n144.8,-3813489.859, 3554304.363, 3662746.118\n144.9,-3813489.819, 3554303.785, 3662746.717\n145.0,-3813489.774, 3554303.209, 3662747.318\n145.1,-3813489.723, 3554302.637, 3662747.922\n145.2,-3813489.667, 3554302.068, 3662748.528\n145.3,-3813489.606, 3554301.503, 3662749.137\n145.4,-3813489.538, 3554300.941, 3662749.749\n145.5,-3813489.465, 3554300.382, 3662750.363\n145.6,-3813489.387, 3554299.827, 3662750.979\n145.7,-3813489.303, 3554299.275, 3662751.598\n145.8,-3813489.214, 3554298.726, 3662752.219\n145.9,-3813489.119, 3554298.181, 3662752.842\n146.0,-3813489.018, 3554297.640, 3662753.468\n146.1,-3813488.913, 3554297.103, 3662754.095\n146.2,-3813488.801, 3554296.569, 3662754.725\n146.3,-3813488.684, 3554296.038, 3662755.358\n146.4,-3813488.562, 3554295.512, 3662755.992\n146.5,-3813488.434, 3554294.989, 3662756.628\n146.6,-3813488.301, 3554294.470, 3662757.266\n146.7,-3813488.162, 3554293.955, 3662757.906\n146.8,-3813488.018, 3554293.443, 3662758.548\n146.9,-3813487.868, 3554292.936, 3662759.192\n147.0,-3813487.713, 3554292.432, 3662759.838\n147.1,-3813487.552, 3554291.933, 3662760.485\n147.2,-3813487.386, 3554291.437, 3662761.134\n147.3,-3813487.215, 3554290.946, 3662761.785\n147.4,-3813487.038, 3554290.459, 3662762.438\n147.5,-3813486.856, 3554289.975, 3662763.092\n147.6,-3813486.669, 3554289.496, 3662763.747\n147.7,-3813486.476, 3554289.021, 3662764.404\n147.8,-3813486.278, 3554288.551, 3662765.063\n147.9,-3813486.075, 3554288.084, 3662765.723\n148.0,-3813485.866, 3554287.622, 3662766.384\n148.1,-3813485.652, 3554287.164, 3662767.047\n148.2,-3813485.433, 3554286.711, 3662767.711\n148.3,-3813485.209, 3554286.261, 3662768.376\n148.4,-3813484.979, 3554285.817, 3662769.042\n148.5,-3813484.744, 3554285.376, 3662769.709\n148.6,-3813484.504, 3554284.941, 3662770.378\n148.7,-3813484.259, 3554284.509, 3662771.047\n148.8,-3813484.008, 3554284.082, 3662771.718\n148.9,-3813483.752, 3554283.660, 3662772.389\n149.0,-3813483.492, 3554283.242, 3662773.061\n149.1,-3813483.226, 3554282.829, 3662773.734\n149.2,-3813482.955, 3554282.421, 3662774.408\n149.3,-3813482.679, 3554282.017, 3662775.083\n149.4,-3813482.397, 3554281.618, 3662775.758\n149.5,-3813482.111, 3554281.224, 3662776.434\n149.6,-3813481.820, 3554280.834, 3662777.111\n149.7,-3813481.524, 3554280.450, 3662777.788\n149.8,-3813481.223, 3554280.070, 3662778.466\n149.9,-3813480.916, 3554279.694, 3662779.144\n150.0,-3813480.605, 3554279.324, 3662779.823\n150.1,-3813480.289, 3554278.959, 3662780.502\n150.2,-3813479.968, 3554278.598, 3662781.181\n150.3,-3813479.643, 3554278.243, 3662781.861\n150.4,-3813479.312, 3554277.892, 3662782.541\n150.5,-3813478.976, 3554277.547, 3662783.221\n150.6,-3813478.636, 3554277.206, 3662783.901\n150.7,-3813478.291, 3554276.871, 3662784.581\n150.8,-3813477.941, 3554276.540, 3662785.262\n150.9,-3813477.587, 3554276.215, 3662785.942\n151.0,-3813477.227, 3554275.894, 3662786.622\n151.1,-3813476.863, 3554275.579, 3662787.302\n151.2,-3813476.495, 3554275.269, 3662787.982\n151.3,-3813476.121, 3554274.964, 3662788.662\n151.4,-3813475.744, 3554274.665, 3662789.342\n151.5,-3813475.361, 3554274.370, 3662790.021\n151.6,-3813474.974, 3554274.081, 3662790.700\n151.7,-3813474.583, 3554273.797, 3662791.379\n151.8,-3813474.187, 3554273.518, 3662792.057\n151.9,-3813473.786, 3554273.245, 3662792.735\n152.0,-3813473.381, 3554272.977, 3662793.412\n152.1,-3813472.972, 3554272.714, 3662794.089\n152.2,-3813472.558, 3554272.457, 3662794.765\n152.3,-3813472.140, 3554272.205, 3662795.440\n152.4,-3813471.718, 3554271.958, 3662796.115\n152.5,-3813471.291, 3554271.717, 3662796.788\n152.6,-3813470.860, 3554271.481, 3662797.462\n152.7,-3813470.425, 3554271.250, 3662798.134\n152.8,-3813469.985, 3554271.025, 3662798.805\n152.9,-3813469.541, 3554270.806, 3662799.475\n153.0,-3813469.094, 3554270.592, 3662800.145\n153.1,-3813468.642, 3554270.383, 3662800.813\n153.2,-3813468.186, 3554270.180, 3662801.481\n153.3,-3813467.726, 3554269.983, 3662802.147\n153.4,-3813467.262, 3554269.791, 3662802.812\n153.5,-3813466.793, 3554269.604, 3662803.475\n153.6,-3813466.321, 3554269.424, 3662804.138\n153.7,-3813465.845, 3554269.248, 3662804.799\n153.8,-3813465.366, 3554269.079, 3662805.459\n153.9,-3813464.882, 3554268.914, 3662806.117\n154.0,-3813464.394, 3554268.756, 3662806.774\n154.1,-3813463.903, 3554268.603, 3662807.430\n154.2,-3813463.408, 3554268.456, 3662808.084\n154.3,-3813462.909, 3554268.314, 3662808.736\n154.4,-3813462.406, 3554268.178, 3662809.387\n154.5,-3813461.900, 3554268.048, 3662810.036\n154.6,-3813461.391, 3554267.923, 3662810.683\n154.7,-3813460.877, 3554267.804, 3662811.329\n154.8,-3813460.360, 3554267.691, 3662811.972\n154.9,-3813459.840, 3554267.584, 3662812.614\n155.0,-3813459.316, 3554267.482, 3662813.254\n155.1,-3813458.788, 3554267.386, 3662813.892\n155.2,-3813458.258, 3554267.295, 3662814.528\n155.3,-3813457.724, 3554267.211, 3662815.162\n155.4,-3813457.186, 3554267.132, 3662815.794\n155.5,-3813456.645, 3554267.058, 3662816.424\n155.6,-3813456.101, 3554266.991, 3662817.052\n155.7,-3813455.554, 3554266.929, 3662817.677\n155.8,-3813455.004, 3554266.873, 3662818.300\n155.9,-3813454.450, 3554266.823, 3662818.921\n156.0,-3813453.894, 3554266.778, 3662819.540\n156.1,-3813453.334, 3554266.740, 3662820.156\n156.2,-3813452.771, 3554266.707, 3662820.770\n156.3,-3813452.205, 3554266.679, 3662821.381\n156.4,-3813451.637, 3554266.658, 3662821.990\n156.5,-3813451.065, 3554266.642, 3662822.596\n156.6,-3813450.491, 3554266.632, 3662823.200\n156.7,-3813449.913, 3554266.628, 3662823.801\n156.8,-3813449.333, 3554266.630, 3662824.399\n156.9,-3813448.751, 3554266.637, 3662824.995\n157.0,-3813448.165, 3554266.650, 3662825.587\n157.1,-3813447.577, 3554266.669, 3662826.177\n157.2,-3813446.986, 3554266.694, 3662826.765\n157.3,-3813446.393, 3554266.724, 3662827.349\n157.4,-3813445.797, 3554266.761, 3662827.930\n157.5,-3813445.198, 3554266.803, 3662828.509\n157.6,-3813444.597, 3554266.850, 3662829.084\n157.7,-3813443.994, 3554266.904, 3662829.656\n157.8,-3813443.388, 3554266.963, 3662830.226\n157.9,-3813442.780, 3554267.028, 3662830.792\n158.0,-3813442.170, 3554267.099, 3662831.355\n158.1,-3813441.557, 3554267.175, 3662831.915\n158.2,-3813440.943, 3554267.258, 3662832.471\n158.3,-3813440.326, 3554267.345, 3662833.024\n158.4,-3813439.707, 3554267.439, 3662833.574\n158.5,-3813439.086, 3554267.538, 3662834.121\n158.6,-3813438.462, 3554267.644, 3662834.664\n158.7,-3813437.837, 3554267.754, 3662835.204\n158.8,-3813437.210, 3554267.871, 3662835.740\n158.9,-3813436.581, 3554267.993, 3662836.273\n159.0,-3813435.950, 3554268.121, 3662836.802\n159.1,-3813435.318, 3554268.254, 3662837.328\n159.2,-3813434.683, 3554268.393, 3662837.850\n159.3,-3813434.047, 3554268.538, 3662838.368\n159.4,-3813433.409, 3554268.688, 3662838.883\n159.5,-3813432.769, 3554268.845, 3662839.394\n159.6,-3813432.128, 3554269.006, 3662839.901\n159.7,-3813431.486, 3554269.173, 3662840.405\n159.8,-3813430.841, 3554269.346, 3662840.904\n159.9,-3813430.196, 3554269.525, 3662841.400\n160.0,-3813429.549, 3554269.709, 3662841.892\n160.1,-3813428.900, 3554269.898, 3662842.380\n160.2,-3813428.250, 3554270.093, 3662842.863\n160.3,-3813427.599, 3554270.294, 3662843.343\n160.4,-3813426.947, 3554270.500, 3662843.819\n160.5,-3813426.294, 3554270.712, 3662844.291\n160.6,-3813425.639, 3554270.929, 3662844.759\n160.7,-3813424.983, 3554271.151, 3662845.222\n160.8,-3813424.326, 3554271.380, 3662845.682\n160.9,-3813423.669, 3554271.613, 3662846.137\n161.0,-3813423.010, 3554271.852, 3662846.588\n161.1,-3813422.350, 3554272.096, 3662847.035\n161.2,-3813421.690, 3554272.346, 3662847.477\n161.3,-3813421.028, 3554272.601, 3662847.915\n161.4,-3813420.366, 3554272.861, 3662848.349\n161.5,-3813419.703, 3554273.127, 3662848.778\n161.6,-3813419.040, 3554273.398, 3662849.203\n161.7,-3813418.375, 3554273.675, 3662849.624\n161.8,-3813417.710, 3554273.956, 3662850.040\n161.9,-3813417.045, 3554274.243, 3662850.451\n162.0,-3813416.379, 3554274.535, 3662850.858\n162.1,-3813415.713, 3554274.833, 3662851.261\n162.2,-3813415.046, 3554275.135, 3662851.659\n162.3,-3813414.379, 3554275.443, 3662852.052\n162.4,-3813413.712, 3554275.756, 3662852.441\n162.5,-3813413.044, 3554276.074, 3662852.825\n162.6,-3813412.376, 3554276.397, 3662853.204\n162.7,-3813411.708, 3554276.726, 3662853.578\n162.8,-3813411.039, 3554277.059, 3662853.948\n162.9,-3813410.371, 3554277.397, 3662854.313\n163.0,-3813409.703, 3554277.741, 3662854.673\n163.1,-3813409.034, 3554278.089, 3662855.029\n163.2,-3813408.366, 3554278.442, 3662855.379\n163.3,-3813407.698, 3554278.801, 3662855.725\n163.4,-3813407.030, 3554279.164, 3662856.066\n163.5,-3813406.362, 3554279.532, 3662856.402\n163.6,-3813405.694, 3554279.905, 3662856.733\n163.7,-3813405.027, 3554280.283, 3662857.059\n163.8,-3813404.360, 3554280.666, 3662857.380\n163.9,-3813403.693, 3554281.053, 3662857.696\n164.0,-3813403.027, 3554281.445, 3662858.007\n164.1,-3813402.361, 3554281.842, 3662858.312\n164.2,-3813401.696, 3554282.244, 3662858.613\n164.3,-3813401.031, 3554282.650, 3662858.909\n164.4,-3813400.367, 3554283.061, 3662859.200\n164.5,-3813399.703, 3554283.477, 3662859.485\n164.6,-3813399.040, 3554283.897, 3662859.765\n164.7,-3813398.378, 3554284.322, 3662860.040\n164.8,-3813397.717, 3554284.752, 3662860.310\n164.9,-3813397.057, 3554285.185, 3662860.575\n165.0,-3813396.397, 3554285.624, 3662860.835\n165.1,-3813395.739, 3554286.067, 3662861.089\n165.2,-3813395.081, 3554286.514, 3662861.338\n165.3,-3813394.425, 3554286.965, 3662861.582\n165.4,-3813393.769, 3554287.421, 3662861.820\n165.5,-3813393.115, 3554287.882, 3662862.053\n165.6,-3813392.461, 3554288.346, 3662862.281\n165.7,-3813391.809, 3554288.815, 3662862.503\n165.8,-3813391.159, 3554289.288, 3662862.720\n165.9,-3813390.509, 3554289.766, 3662862.932\n166.0,-3813389.861, 3554290.247, 3662863.138\n166.1,-3813389.214, 3554290.733, 3662863.339\n166.2,-3813388.569, 3554291.222, 3662863.534\n166.3,-3813387.925, 3554291.716, 3662863.724\n166.4,-3813387.283, 3554292.214, 3662863.909\n166.5,-3813386.642, 3554292.715, 3662864.088\n166.6,-3813386.003, 3554293.221, 3662864.261\n166.7,-3813385.365, 3554293.731, 3662864.430\n166.8,-3813384.729, 3554294.244, 3662864.592\n166.9,-3813384.095, 3554294.762, 3662864.749\n167.0,-3813383.463, 3554295.283, 3662864.901\n167.1,-3813382.832, 3554295.808, 3662865.047\n167.2,-3813382.204, 3554296.336, 3662865.187\n167.3,-3813381.577, 3554296.869, 3662865.322\n167.4,-3813380.952, 3554297.405, 3662865.452\n167.5,-3813380.329, 3554297.945, 3662865.575\n167.6,-3813379.709, 3554298.488, 3662865.694\n167.7,-3813379.090, 3554299.035, 3662865.806\n167.8,-3813378.473, 3554299.585, 3662865.913\n167.9,-3813377.859, 3554300.139, 3662866.015\n168.0,-3813377.247, 3554300.696, 3662866.111\n168.1,-3813376.637, 3554301.257, 3662866.201\n168.2,-3813376.030, 3554301.821, 3662866.285\n168.3,-3813375.424, 3554302.388, 3662866.364\n168.4,-3813374.822, 3554302.959, 3662866.438\n168.5,-3813374.221, 3554303.533, 3662866.505\n168.6,-3813373.623, 3554304.110, 3662866.567\n168.7,-3813373.028, 3554304.691, 3662866.624\n168.8,-3813372.435, 3554305.274, 3662866.675\n168.9,-3813371.845, 3554305.860, 3662866.720\n169.0,-3813371.257, 3554306.450, 3662866.759\n169.1,-3813370.672, 3554307.043, 3662866.793\n169.2,-3813370.090, 3554307.638, 3662866.821\n169.3,-3813369.510, 3554308.237, 3662866.844\n169.4,-3813368.934, 3554308.838, 3662866.860\n169.5,-3813368.360, 3554309.442, 3662866.871\n169.6,-3813367.789, 3554310.049, 3662866.877\n169.7,-3813367.221, 3554310.659, 3662866.877\n169.8,-3813366.656, 3554311.271, 3662866.871\n169.9,-3813366.094, 3554311.886, 3662866.859\n170.0,-3813365.535, 3554312.504, 3662866.842\n170.1,-3813364.978, 3554313.124, 3662866.819\n170.2,-3813364.426, 3554313.747, 3662866.790\n170.3,-3813363.876, 3554314.372, 3662866.756\n170.4,-3813363.329, 3554315.000, 3662866.716\n170.5,-3813362.786, 3554315.630, 3662866.671\n170.6,-3813362.246, 3554316.263, 3662866.620\n170.7,-3813361.709, 3554316.898, 3662866.563\n170.8,-3813361.176, 3554317.535, 3662866.500\n170.9,-3813360.646, 3554318.174, 3662866.432\n171.0,-3813360.119, 3554318.816, 3662866.358\n171.1,-3813359.596, 3554319.460, 3662866.279\n171.2,-3813359.076, 3554320.105, 3662866.194\n171.3,-3813358.560, 3554320.753, 3662866.103\n171.4,-3813358.047, 3554321.403, 3662866.007\n171.5,-3813357.538, 3554322.055, 3662865.905\n171.6,-3813357.033, 3554322.709, 3662865.798\n171.7,-3813356.531, 3554323.365, 3662865.684\n171.8,-3813356.033, 3554324.022, 3662865.566\n171.9,-3813355.539, 3554324.681, 3662865.441\n172.0,-3813355.048, 3554325.342, 3662865.312\n172.1,-3813354.561, 3554326.005, 3662865.176\n172.2,-3813354.078, 3554326.669, 3662865.035\n172.3,-3813353.599, 3554327.335, 3662864.889\n172.4,-3813353.124, 3554328.003, 3662864.737\n172.5,-3813352.653, 3554328.672, 3662864.579\n172.6,-3813352.186, 3554329.342, 3662864.416\n172.7,-3813351.722, 3554330.014, 3662864.248\n172.8,-3813351.263, 3554330.687, 3662864.074\n172.9,-3813350.808, 3554331.362, 3662863.894\n173.0,-3813350.357, 3554332.038, 3662863.709\n173.1,-3813349.910, 3554332.715, 3662863.519\n173.2,-3813349.467, 3554333.393, 3662863.323\n173.3,-3813349.028, 3554334.072, 3662863.122\n173.4,-3813348.594, 3554334.753, 3662862.915\n173.5,-3813348.164, 3554335.434, 3662862.703\n173.6,-3813347.738, 3554336.117, 3662862.486\n173.7,-3813347.316, 3554336.800, 3662862.263\n173.8,-3813346.899, 3554337.485, 3662862.035\n173.9,-3813346.486, 3554338.170, 3662861.801\n174.0,-3813346.078, 3554338.856, 3662861.562\n174.1,-3813345.674, 3554339.543, 3662861.318\n174.2,-3813345.274, 3554340.230, 3662861.069\n174.3,-3813344.879, 3554340.918, 3662860.814\n174.4,-3813344.489, 3554341.607, 3662860.554\n174.5,-3813344.103, 3554342.296, 3662860.289\n174.6,-3813343.721, 3554342.986, 3662860.019\n174.7,-3813343.344, 3554343.676, 3662859.743\n174.8,-3813342.972, 3554344.367, 3662859.462\n174.9,-3813342.604, 3554345.058, 3662859.177\n175.0,-3813342.241, 3554345.749, 3662858.886\n175.1,-3813341.883, 3554346.441, 3662858.589\n175.2,-3813341.529, 3554347.133, 3662858.288\n175.3,-3813341.180, 3554347.825, 3662857.982\n175.4,-3813340.836, 3554348.517, 3662857.671\n175.5,-3813340.497, 3554349.209, 3662857.354\n175.6,-3813340.163, 3554349.902, 3662857.033\n175.7,-3813339.833, 3554350.594, 3662856.706\n175.8,-3813339.508, 3554351.286, 3662856.375\n175.9,-3813339.188, 3554351.978, 3662856.039\n176.0,-3813338.873, 3554352.670, 3662855.698\n176.1,-3813338.563, 3554353.362, 3662855.352\n176.2,-3813338.258, 3554354.053, 3662855.001\n176.3,-3813337.958, 3554354.744, 3662854.645\n176.4,-3813337.663, 3554355.435, 3662854.284\n176.5,-3813337.372, 3554356.126, 3662853.919\n176.6,-3813337.087, 3554356.816, 3662853.549\n176.7,-3813336.807, 3554357.505, 3662853.174\n176.8,-3813336.532, 3554358.194, 3662852.794\n176.9,-3813336.262, 3554358.883, 3662852.410\n177.0,-3813335.997, 3554359.570, 3662852.021\n177.1,-3813335.737, 3554360.257, 3662851.627\n177.2,-3813335.483, 3554360.944, 3662851.229\n177.3,-3813335.233, 3554361.629, 3662850.826\n177.4,-3813334.989, 3554362.314, 3662850.419\n177.5,-3813334.750, 3554362.998, 3662850.007\n177.6,-3813334.516, 3554363.681, 3662849.590\n177.7,-3813334.288, 3554364.363, 3662849.169\n177.8,-3813334.064, 3554365.043, 3662848.744\n177.9,-3813333.846, 3554365.723, 3662848.314\n178.0,-3813333.633, 3554366.402, 3662847.880\n178.1,-3813333.426, 3554367.080, 3662847.442\n178.2,-3813333.223, 3554367.756, 3662846.999\n178.3,-3813333.026, 3554368.431, 3662846.552\n178.4,-3813332.835, 3554369.105, 3662846.101\n178.5,-3813332.648, 3554369.777, 3662845.645\n178.6,-3813332.468, 3554370.448, 3662845.185\n178.7,-3813332.292, 3554371.118, 3662844.722\n178.8,-3813332.122, 3554371.786, 3662844.253\n178.9,-3813331.957, 3554372.453, 3662843.781\n179.0,-3813331.798, 3554373.118, 3662843.305\n179.1,-3813331.644, 3554373.781, 3662842.825\n179.2,-3813331.495, 3554374.443, 3662842.341\n179.3,-3813331.352, 3554375.103, 3662841.852\n179.4,-3813331.214, 3554375.761, 3662841.360\n179.5,-3813331.082, 3554376.418, 3662840.864\n179.6,-3813330.955, 3554377.072, 3662840.364\n179.7,-3813330.834, 3554377.725, 3662839.861\n179.8,-3813330.718, 3554378.376, 3662839.353\n179.9,-3813330.608, 3554379.025, 3662838.842\n180.0,-3813330.503, 3554379.671, 3662838.327\n180.1,-3813330.404, 3554380.316, 3662837.808\n180.2,-3813330.310, 3554380.958, 3662837.286\n180.3,-3813330.222, 3554381.599, 3662836.760\n180.4,-3813330.139, 3554382.237, 3662836.230\n180.5,-3813330.062, 3554382.873, 3662835.697\n180.6,-3813329.990, 3554383.506, 3662835.161\n180.7,-3813329.924, 3554384.138, 3662834.621\n180.8,-3813329.864, 3554384.766, 3662834.077\n180.9,-3813329.809, 3554385.393, 3662833.531\n181.0,-3813329.759, 3554386.017, 3662832.980\n181.1,-3813329.715, 3554386.638, 3662832.427\n181.2,-3813329.677, 3554387.257, 3662831.870\n181.3,-3813329.644, 3554387.873, 3662831.310\n181.4,-3813329.617, 3554388.487, 3662830.747\n181.5,-3813329.595, 3554389.098, 3662830.180\n181.6,-3813329.579, 3554389.706, 3662829.611\n181.7,-3813329.568, 3554390.311, 3662829.038\n181.8,-3813329.563, 3554390.914, 3662828.463\n181.9,-3813329.564, 3554391.513, 3662827.884\n182.0,-3813329.570, 3554392.110, 3662827.302\n182.1,-3813329.582, 3554392.704, 3662826.718\n182.2,-3813329.599, 3554393.295, 3662826.130\n182.3,-3813329.622, 3554393.882, 3662825.540\n182.4,-3813329.651, 3554394.467, 3662824.947\n182.5,-3813329.685, 3554395.049, 3662824.351\n182.6,-3813329.724, 3554395.627, 3662823.753\n182.7,-3813329.769, 3554396.203, 3662823.152\n182.8,-3813329.820, 3554396.775, 3662822.548\n182.9,-3813329.876, 3554397.344, 3662821.941\n183.0,-3813329.938, 3554397.909, 3662821.332\n183.1,-3813330.005, 3554398.471, 3662820.721\n183.2,-3813330.078, 3554399.030, 3662820.107\n183.3,-3813330.156, 3554399.585, 3662819.491\n183.4,-3813330.240, 3554400.137, 3662818.872\n183.5,-3813330.330, 3554400.685, 3662818.251\n183.6,-3813330.425, 3554401.230, 3662817.627\n183.7,-3813330.525, 3554401.772, 3662817.002\n183.8,-3813330.631, 3554402.309, 3662816.374\n183.9,-3813330.743, 3554402.843, 3662815.744\n184.0,-3813330.860, 3554403.373, 3662815.112\n184.1,-3813330.982, 3554403.900, 3662814.478\n184.2,-3813331.110, 3554404.423, 3662813.841\n184.3,-3813331.243, 3554404.942, 3662813.203\n184.4,-3813331.382, 3554405.457, 3662812.563\n184.5,-3813331.527, 3554405.968, 3662811.921\n184.6,-3813331.676, 3554406.476, 3662811.277\n184.7,-3813331.831, 3554406.979, 3662810.632\n184.8,-3813331.992, 3554407.479, 3662809.984\n184.9,-3813332.158, 3554407.974, 3662809.335\n185.0,-3813332.329, 3554408.465, 3662808.684\n185.1,-3813332.506, 3554408.953, 3662808.032\n185.2,-3813332.688, 3554409.436, 3662807.377\n185.3,-3813332.875, 3554409.915, 3662806.722\n185.4,-3813333.068, 3554410.390, 3662806.065\n185.5,-3813333.266, 3554410.861, 3662805.406\n185.6,-3813333.470, 3554411.327, 3662804.746\n185.7,-3813333.678, 3554411.789, 3662804.085\n185.8,-3813333.892, 3554412.247, 3662803.422\n185.9,-3813334.112, 3554412.700, 3662802.759\n186.0,-3813334.336, 3554413.150, 3662802.093\n186.1,-3813334.566, 3554413.594, 3662801.427\n186.2,-3813334.801, 3554414.034, 3662800.760\n186.3,-3813335.041, 3554414.470, 3662800.091\n186.4,-3813335.286, 3554414.902, 3662799.422\n186.5,-3813335.537, 3554415.328, 3662798.751\n186.6,-3813335.793, 3554415.751, 3662798.080\n186.7,-3813336.054, 3554416.168, 3662797.408\n186.8,-3813336.320, 3554416.581, 3662796.735\n186.9,-3813336.591, 3554416.990, 3662796.061\n187.0,-3813336.867, 3554417.393, 3662795.386\n187.1,-3813337.148, 3554417.792, 3662794.711\n187.2,-3813337.434, 3554418.187, 3662794.034\n187.3,-3813337.725, 3554418.576, 3662793.358\n187.4,-3813338.022, 3554418.961, 3662792.681\n187.5,-3813338.323, 3554419.341, 3662792.003\n187.6,-3813338.629, 3554419.716, 3662791.325\n187.7,-3813338.940, 3554420.086, 3662790.646\n187.8,-3813339.256, 3554420.451, 3662789.967\n187.9,-3813339.577, 3554420.812, 3662789.288\n188.0,-3813339.903, 3554421.167, 3662788.608\n188.1,-3813340.234, 3554421.518, 3662787.928\n188.2,-3813340.569, 3554421.863, 3662787.248\n188.3,-3813340.910, 3554422.204, 3662786.568\n188.4,-3813341.255, 3554422.539, 3662785.888\n188.5,-3813341.605, 3554422.870, 3662785.207\n188.6,-3813341.959, 3554423.195, 3662784.527\n188.7,-3813342.319, 3554423.515, 3662783.847\n188.8,-3813342.683, 3554423.831, 3662783.166\n188.9,-3813343.051, 3554424.140, 3662782.486\n189.0,-3813343.425, 3554424.445, 3662781.807\n189.1,-3813343.803, 3554424.745, 3662781.127\n189.2,-3813344.185, 3554425.039, 3662780.448\n189.3,-3813344.572, 3554425.328, 3662779.769\n189.4,-3813344.964, 3554425.612, 3662779.090\n189.5,-3813345.360, 3554425.891, 3662778.412\n189.6,-3813345.760, 3554426.164, 3662777.734\n189.7,-3813346.165, 3554426.432, 3662777.057\n189.8,-3813346.575, 3554426.695, 3662776.380\n189.9,-3813346.988, 3554426.953, 3662775.704\n190.0,-3813347.407, 3554427.205, 3662775.029\n190.1,-3813347.829, 3554427.451, 3662774.354\n190.2,-3813348.256, 3554427.692, 3662773.681\n190.3,-3813348.687, 3554427.928, 3662773.007\n190.4,-3813349.122, 3554428.159, 3662772.335\n190.5,-3813349.562, 3554428.384, 3662771.664\n190.6,-3813350.005, 3554428.603, 3662770.994\n190.7,-3813350.453, 3554428.817, 3662770.324\n190.8,-3813350.905, 3554429.025, 3662769.656\n190.9,-3813351.361, 3554429.228, 3662768.989\n191.0,-3813351.821, 3554429.426, 3662768.322\n191.1,-3813352.285, 3554429.618, 3662767.657\n191.2,-3813352.754, 3554429.804, 3662766.994\n191.3,-3813353.226, 3554429.985, 3662766.331\n191.4,-3813353.702, 3554430.160, 3662765.670\n191.5,-3813354.182, 3554430.330, 3662765.010\n191.6,-3813354.665, 3554430.494, 3662764.352\n191.7,-3813355.153, 3554430.652, 3662763.695\n191.8,-3813355.644, 3554430.805, 3662763.039\n191.9,-3813356.139, 3554430.952, 3662762.385\n192.0,-3813356.638, 3554431.094, 3662761.733\n192.1,-3813357.141, 3554431.230, 3662761.082\n192.2,-3813357.647, 3554431.360, 3662760.433\n192.3,-3813358.157, 3554431.485, 3662759.786\n192.4,-3813358.670, 3554431.604, 3662759.141\n192.5,-3813359.187, 3554431.717, 3662758.497\n192.6,-3813359.708, 3554431.824, 3662757.855\n192.7,-3813360.232, 3554431.926, 3662757.215\n192.8,-3813360.759, 3554432.022, 3662756.577\n192.9,-3813361.290, 3554432.112, 3662755.941\n193.0,-3813361.824, 3554432.197, 3662755.307\n193.1,-3813362.361, 3554432.276, 3662754.675\n193.2,-3813362.902, 3554432.349, 3662754.045\n193.3,-3813363.446, 3554432.417, 3662753.418\n193.4,-3813363.994, 3554432.478, 3662752.792\n193.5,-3813364.544, 3554432.534, 3662752.169\n193.6,-3813365.098, 3554432.585, 3662751.548\n193.7,-3813365.654, 3554432.629, 3662750.930\n193.8,-3813366.214, 3554432.668, 3662750.313\n193.9,-3813366.777, 3554432.701, 3662749.700\n194.0,-3813367.342, 3554432.728, 3662749.088\n194.1,-3813367.911, 3554432.749, 3662748.480\n194.2,-3813368.483, 3554432.765, 3662747.874\n194.3,-3813369.057, 3554432.775, 3662747.270\n194.4,-3813369.635, 3554432.779, 3662746.669\n194.5,-3813370.215, 3554432.777, 3662746.071\n194.6,-3813370.797, 3554432.770, 3662745.475\n194.7,-3813371.383, 3554432.756, 3662744.882\n194.8,-3813371.971, 3554432.737, 3662744.292\n194.9,-3813372.562, 3554432.713, 3662743.705\n195.0,-3813373.155, 3554432.682, 3662743.121\n195.1,-3813373.751, 3554432.646, 3662742.540\n195.2,-3813374.350, 3554432.604, 3662741.961\n195.3,-3813374.951, 3554432.556, 3662741.386\n195.4,-3813375.554, 3554432.503, 3662740.813\n195.5,-3813376.160, 3554432.443, 3662740.244\n195.6,-3813376.768, 3554432.378, 3662739.678\n195.7,-3813377.378, 3554432.307, 3662739.115\n195.8,-3813377.991, 3554432.231, 3662738.555\n195.9,-3813378.606, 3554432.149, 3662737.999\n196.0,-3813379.223, 3554432.061, 3662737.446\n196.1,-3813379.842, 3554431.967, 3662736.896\n196.2,-3813380.463, 3554431.868, 3662736.349\n196.3,-3813381.086, 3554431.762, 3662735.806\n196.4,-3813381.711, 3554431.652, 3662735.266\n196.5,-3813382.338, 3554431.535, 3662734.730\n196.6,-3813382.967, 3554431.413, 3662734.197\n196.7,-3813383.598, 3554431.285, 3662733.668\n196.8,-3813384.231, 3554431.152, 3662733.142\n196.9,-3813384.865, 3554431.012, 3662732.620\n197.0,-3813385.502, 3554430.868, 3662732.102\n197.1,-3813386.140, 3554430.717, 3662731.587\n197.2,-3813386.779, 3554430.561, 3662731.077\n197.3,-3813387.420, 3554430.399, 3662730.569\n197.4,-3813388.063, 3554430.232, 3662730.066\n197.5,-3813388.707, 3554430.059, 3662729.566\n197.6,-3813389.353, 3554429.881, 3662729.071\n197.7,-3813390.000, 3554429.697, 3662728.579\n197.8,-3813390.648, 3554429.507, 3662728.091\n197.9,-3813391.298, 3554429.312, 3662727.607\n198.0,-3813391.949, 3554429.111, 3662727.127\n198.1,-3813392.602, 3554428.905, 3662726.652\n198.2,-3813393.255, 3554428.693, 3662726.180\n198.3,-3813393.910, 3554428.476, 3662725.712\n198.4,-3813394.565, 3554428.253, 3662725.249\n198.5,-3813395.222, 3554428.025, 3662724.789\n198.6,-3813395.880, 3554427.792, 3662724.334\n198.7,-3813396.539, 3554427.553, 3662723.883\n198.8,-3813397.198, 3554427.309, 3662723.436\n198.9,-3813397.859, 3554427.059, 3662722.994\n199.0,-3813398.520, 3554426.804, 3662722.556\n199.1,-3813399.183, 3554426.543, 3662722.122\n199.2,-3813399.846, 3554426.277, 3662721.693\n199.3,-3813400.509, 3554426.006, 3662721.268\n199.4,-3813401.173, 3554425.730, 3662720.847\n199.5,-3813401.838, 3554425.448, 3662720.431\n199.6,-3813402.504, 3554425.161, 3662720.020\n199.7,-3813403.170, 3554424.869, 3662719.613\n199.8,-3813403.836, 3554424.571, 3662719.211\n199.9,-3813404.503, 3554424.269, 3662718.813\n200.0,-3813405.170, 3554423.961, 3662718.419\n200.1,-3813405.837, 3554423.648, 3662718.031\n200.2,-3813406.505, 3554423.330, 3662717.647\n200.3,-3813407.173, 3554423.007, 3662717.268\n200.4,-3813407.841, 3554422.678, 3662716.893\n200.5,-3813408.509, 3554422.345, 3662716.524\n200.6,-3813409.178, 3554422.007, 3662716.159\n200.7,-3813409.846, 3554421.663, 3662715.798\n200.8,-3813410.514, 3554421.315, 3662715.443\n200.9,-3813411.183, 3554420.961, 3662715.092\n201.0,-3813411.851, 3554420.603, 3662714.747\n201.1,-3813412.519, 3554420.240, 3662714.406\n201.2,-3813413.187, 3554419.872, 3662714.070\n201.3,-3813413.855, 3554419.498, 3662713.739\n201.4,-3813414.522, 3554419.121, 3662713.413\n201.5,-3813415.189, 3554418.738, 3662713.092\n201.6,-3813415.856, 3554418.350, 3662712.777\n201.7,-3813416.522, 3554417.958, 3662712.466\n201.8,-3813417.188, 3554417.561, 3662712.160\n201.9,-3813417.853, 3554417.159, 3662711.859\n202.0,-3813418.518, 3554416.753, 3662711.563\n202.1,-3813419.182, 3554416.342, 3662711.273\n202.2,-3813419.845, 3554415.926, 3662710.987\n202.3,-3813420.508, 3554415.506, 3662710.707\n202.4,-3813421.170, 3554415.081, 3662710.432\n202.5,-3813421.831, 3554414.652, 3662710.162\n202.6,-3813422.492, 3554414.218, 3662709.897\n202.7,-3813423.151, 3554413.779, 3662709.638\n202.8,-3813423.810, 3554413.336, 3662709.384\n202.9,-3813424.467, 3554412.889, 3662709.135\n203.0,-3813425.124, 3554412.437, 3662708.891\n203.1,-3813425.780, 3554411.981, 3662708.653\n203.2,-3813426.434, 3554411.521, 3662708.420\n203.3,-3813427.087, 3554411.056, 3662708.192\n203.4,-3813427.739, 3554410.588, 3662707.970\n203.5,-3813428.390, 3554410.114, 3662707.753\n203.6,-3813429.039, 3554409.637, 3662707.541\n203.7,-3813429.688, 3554409.156, 3662707.335\n203.8,-3813430.334, 3554408.670, 3662707.134\n203.9,-3813430.980, 3554408.180, 3662706.939\n204.0,-3813431.624, 3554407.687, 3662706.749\n204.1,-3813432.266, 3554407.189, 3662706.565\n204.2,-3813432.907, 3554406.687, 3662706.386\n204.3,-3813433.546, 3554406.181, 3662706.212\n204.4,-3813434.184, 3554405.672, 3662706.044\n204.5,-3813434.819, 3554405.158, 3662705.881\n204.6,-3813435.453, 3554404.641, 3662705.724\n204.7,-3813436.086, 3554404.119, 3662705.573\n204.8,-3813436.716, 3554403.595, 3662705.427\n204.9,-3813437.345, 3554403.066, 3662705.286\n205.0,-3813437.972, 3554402.533, 3662705.152\n205.1,-3813438.596, 3554401.997, 3662705.022\n205.2,-3813439.219, 3554401.457, 3662704.898\n205.3,-3813439.840, 3554400.914, 3662704.780\n205.4,-3813440.458, 3554400.367, 3662704.668\n205.5,-3813441.075, 3554399.817, 3662704.561\n205.6,-3813441.689, 3554399.263, 3662704.459\n205.7,-3813442.301, 3554398.706, 3662704.364\n205.8,-3813442.911, 3554398.145, 3662704.273\n205.9,-3813443.519, 3554397.581, 3662704.189\n206.0,-3813444.124, 3554397.013, 3662704.110\n206.1,-3813444.727, 3554396.443, 3662704.037\n206.2,-3813445.327, 3554395.869, 3662703.969\n206.3,-3813445.925, 3554395.292, 3662703.907\n206.4,-3813446.520, 3554394.711, 3662703.851\n206.5,-3813447.113, 3554394.128, 3662703.800\n206.6,-3813447.703, 3554393.541, 3662703.755\n206.7,-3813448.291, 3554392.952, 3662703.715\n206.8,-3813448.876, 3554392.359, 3662703.682\n206.9,-3813449.458, 3554391.764, 3662703.654\n207.0,-3813450.038, 3554391.165, 3662703.631\n207.1,-3813450.614, 3554390.564, 3662703.615\n207.2,-3813451.188, 3554389.960, 3662703.603\n207.3,-3813451.759, 3554389.353, 3662703.598\n207.4,-3813452.327, 3554388.743, 3662703.598\n207.5,-3813452.892, 3554388.130, 3662703.604\n207.6,-3813453.454, 3554387.515, 3662703.616\n207.7,-3813454.013, 3554386.898, 3662703.633\n207.8,-3813454.569, 3554386.277, 3662703.656\n207.9,-3813455.122, 3554385.654, 3662703.685\n208.0,-3813455.672, 3554385.029, 3662703.719\n208.1,-3813456.218, 3554384.401, 3662703.759\n208.2,-3813456.762, 3554383.771, 3662703.805\n208.3,-3813457.302, 3554383.138, 3662703.856\n208.4,-3813457.838, 3554382.504, 3662703.913\n208.5,-3813458.372, 3554381.866, 3662703.975\n208.6,-3813458.902, 3554381.227, 3662704.044\n208.7,-3813459.429, 3554380.585, 3662704.117\n208.8,-3813459.952, 3554379.942, 3662704.197\n208.9,-3813460.471, 3554379.296, 3662704.282\n209.0,-3813460.988, 3554378.648, 3662704.373\n209.1,-3813461.500, 3554377.998, 3662704.469\n209.2,-3813462.009, 3554377.346, 3662704.571\n209.3,-3813462.515, 3554376.692, 3662704.678\n209.4,-3813463.016, 3554376.037, 3662704.792\n209.5,-3813463.514, 3554375.379, 3662704.910\n209.6,-3813464.009, 3554374.720, 3662705.035\n209.7,-3813464.499, 3554374.059, 3662705.164\n209.8,-3813464.986, 3554373.396, 3662705.300\n209.9,-3813465.469, 3554372.732, 3662705.441\n210.0,-3813465.948, 3554372.066, 3662705.587\n210.1,-3813466.423, 3554371.398, 3662705.739\n210.2,-3813466.894, 3554370.729, 3662705.897\n210.3,-3813467.361, 3554370.059, 3662706.060\n210.4,-3813467.825, 3554369.387, 3662706.229\n210.5,-3813468.284, 3554368.714, 3662706.403\n210.6,-3813468.739, 3554368.039, 3662706.582\n210.7,-3813469.190, 3554367.363, 3662706.767\n210.8,-3813469.637, 3554366.686, 3662706.958\n210.9,-3813470.080, 3554366.008, 3662707.154\n211.0,-3813470.518, 3554365.328, 3662707.355\n211.1,-3813470.953, 3554364.648, 3662707.562\n211.2,-3813471.383, 3554363.966, 3662707.774\n211.3,-3813471.809, 3554363.284, 3662707.991\n211.4,-3813472.230, 3554362.601, 3662708.214\n211.5,-3813472.647, 3554361.916, 3662708.442\n211.6,-3813473.060, 3554361.231, 3662708.676\n211.7,-3813473.468, 3554360.545, 3662708.915\n211.8,-3813473.872, 3554359.858, 3662709.159\n211.9,-3813474.272, 3554359.171, 3662709.408\n212.0,-3813474.667, 3554358.483, 3662709.663\n212.1,-3813475.058, 3554357.794, 3662709.923\n212.2,-3813475.444, 3554357.105, 3662710.188\n212.3,-3813475.825, 3554356.415, 3662710.459\n212.4,-3813476.202, 3554355.725, 3662710.734\n212.5,-3813476.574, 3554355.034, 3662711.015\n212.6,-3813476.942, 3554354.343, 3662711.301\n212.7,-3813477.305, 3554353.652, 3662711.592\n212.8,-3813477.663, 3554352.960, 3662711.888\n212.9,-3813478.017, 3554352.268, 3662712.189\n213.0,-3813478.365, 3554351.576, 3662712.496\n213.1,-3813478.709, 3554350.884, 3662712.807\n213.2,-3813479.049, 3554350.192, 3662713.124\n213.3,-3813479.383, 3554349.499, 3662713.445\n213.4,-3813479.713, 3554348.807, 3662713.771\n213.5,-3813480.038, 3554348.115, 3662714.103\n213.6,-3813480.357, 3554347.423, 3662714.439\n213.7,-3813480.672, 3554346.731, 3662714.780\n213.8,-3813480.983, 3554346.039, 3662715.126\n213.9,-3813481.288, 3554345.347, 3662715.477\n214.0,-3813481.588, 3554344.656, 3662715.833\n214.1,-3813481.883, 3554343.965, 3662716.194\n214.2,-3813482.173, 3554343.275, 3662716.559\n214.3,-3813482.458, 3554342.585, 3662716.930\n214.4,-3813482.738, 3554341.896, 3662717.305\n214.5,-3813483.013, 3554341.207, 3662717.684\n214.6,-3813483.283, 3554340.518, 3662718.069\n214.7,-3813483.548, 3554339.831, 3662718.458\n214.8,-3813483.808, 3554339.143, 3662718.851\n214.9,-3813484.062, 3554338.457, 3662719.250\n215.0,-3813484.312, 3554337.772, 3662719.653\n215.1,-3813484.556, 3554337.087, 3662720.060\n215.2,-3813484.795, 3554336.403, 3662720.472\n215.3,-3813485.029, 3554335.720, 3662720.888\n215.4,-3813485.257, 3554335.038, 3662721.309\n215.5,-3813485.481, 3554334.357, 3662721.735\n215.6,-3813485.699, 3554333.678, 3662722.164\n215.7,-3813485.912, 3554332.999, 3662722.599\n215.8,-3813486.119, 3554332.321, 3662723.037\n215.9,-3813486.321, 3554331.645, 3662723.480\n216.0,-3813486.518, 3554330.970, 3662723.927\n216.1,-3813486.710, 3554330.296, 3662724.378\n216.2,-3813486.896, 3554329.624, 3662724.834\n216.3,-3813487.077, 3554328.952, 3662725.294\n216.4,-3813487.252, 3554328.283, 3662725.758\n216.5,-3813487.423, 3554327.615, 3662726.226\n216.6,-3813487.587, 3554326.948, 3662726.698\n216.7,-3813487.747, 3554326.283, 3662727.174\n216.8,-3813487.900, 3554325.620, 3662727.654\n216.9,-3813488.049, 3554324.958, 3662728.139\n217.0,-3813488.192, 3554324.298, 3662728.627\n217.1,-3813488.330, 3554323.640, 3662729.119\n217.2,-3813488.462, 3554322.983, 3662729.615\n217.3,-3813488.589, 3554322.329, 3662730.115\n217.4,-3813488.710, 3554321.676, 3662730.619\n217.5,-3813488.825, 3554321.025, 3662731.126\n217.6,-3813488.936, 3554320.377, 3662731.638\n217.7,-3813489.040, 3554319.730, 3662732.153\n217.8,-3813489.140, 3554319.085, 3662732.671\n217.9,-3813489.233, 3554318.443, 3662733.194\n218.0,-3813489.322, 3554317.803, 3662733.720\n218.1,-3813489.404, 3554317.164, 3662734.249\n218.2,-3813489.482, 3554316.529, 3662734.782\n218.3,-3813489.553, 3554315.895, 3662735.319\n218.4,-3813489.619, 3554315.264, 3662735.859\n218.5,-3813489.680, 3554314.635, 3662736.402\n218.6,-3813489.735, 3554314.009, 3662736.949\n218.7,-3813489.784, 3554313.385, 3662737.500\n218.8,-3813489.828, 3554312.763, 3662738.053\n218.9,-3813489.866, 3554312.145, 3662738.610\n219.0,-3813489.899, 3554311.528, 3662739.170\n219.1,-3813489.926, 3554310.915, 3662739.733\n219.2,-3813489.948, 3554310.304, 3662740.300\n219.3,-3813489.964, 3554309.696, 3662740.869\n219.4,-3813489.975, 3554309.091, 3662741.442\n219.5,-3813489.979, 3554308.488, 3662742.018\n219.6,-3813489.979, 3554307.888, 3662742.596\n219.7,-3813489.973, 3554307.292, 3662743.178\n219.8,-3813489.961, 3554306.698, 3662743.762\n219.9,-3813489.943, 3554306.107, 3662744.350\n220.0,-3813489.921, 3554305.519, 3662744.940\n220.1,-3813489.892, 3554304.935, 3662745.533\n220.2,-3813489.858, 3554304.353, 3662746.129\n220.3,-3813489.818, 3554303.774, 3662746.728\n220.4,-3813489.773, 3554303.199, 3662747.329\n220.5,-3813489.722, 3554302.627, 3662747.933\n220.6,-3813489.666, 3554302.058, 3662748.539\n220.7,-3813489.604, 3554301.493, 3662749.148\n220.8,-3813489.537, 3554300.931, 3662749.760\n220.9,-3813489.464, 3554300.372, 3662750.374\n221.0,-3813489.386, 3554299.817, 3662750.990\n221.1,-3813489.302, 3554299.265, 3662751.609\n221.2,-3813489.212, 3554298.717, 3662752.230\n221.3,-3813489.117, 3554298.172, 3662752.853\n221.4,-3813489.017, 3554297.631, 3662753.479\n221.5,-3813488.911, 3554297.093, 3662754.107\n221.6,-3813488.799, 3554296.559, 3662754.737\n221.7,-3813488.682, 3554296.029, 3662755.369\n221.8,-3813488.560, 3554295.502, 3662756.003\n221.9,-3813488.432, 3554294.980, 3662756.639\n222.0,-3813488.298, 3554294.461, 3662757.277\n222.1,-3813488.159, 3554293.945, 3662757.918\n222.2,-3813488.015, 3554293.434, 3662758.560\n222.3,-3813487.865, 3554292.927, 3662759.203\n222.4,-3813487.710, 3554292.423, 3662759.849\n222.5,-3813487.549, 3554291.924, 3662760.497\n222.6,-3813487.383, 3554291.429, 3662761.146\n222.7,-3813487.212, 3554290.937, 3662761.797\n222.8,-3813487.035, 3554290.450, 3662762.449\n222.9,-3813486.853, 3554289.967, 3662763.103\n223.0,-3813486.666, 3554289.488, 3662763.759\n223.1,-3813486.473, 3554289.013, 3662764.416\n223.2,-3813486.275, 3554288.542, 3662765.075\n223.3,-3813486.071, 3554288.076, 3662765.735\n223.4,-3813485.863, 3554287.614, 3662766.396\n223.5,-3813485.648, 3554287.156, 3662767.058\n223.6,-3813485.429, 3554286.703, 3662767.722\n223.7,-3813485.205, 3554286.253, 3662768.387\n223.8,-3813484.975, 3554285.809, 3662769.054\n223.9,-3813484.740, 3554285.369, 3662769.721\n224.0,-3813484.500, 3554284.933, 3662770.390\n224.1,-3813484.254, 3554284.502, 3662771.059\n224.2,-3813484.004, 3554284.075, 3662771.729\n224.3,-3813483.748, 3554283.653, 3662772.401\n224.4,-3813483.487, 3554283.235, 3662773.073\n224.5,-3813483.221, 3554282.822, 3662773.746\n224.6,-3813482.950, 3554282.414, 3662774.420\n224.7,-3813482.674, 3554282.010, 3662775.095\n224.8,-3813482.392, 3554281.611, 3662775.770\n224.9,-3813482.106, 3554281.217, 3662776.446\n225.0,-3813481.815, 3554280.827, 3662777.123\n225.1,-3813481.518, 3554280.443, 3662777.800\n225.2,-3813481.217, 3554280.063, 3662778.478\n225.3,-3813480.911, 3554279.688, 3662779.156\n225.4,-3813480.600, 3554279.318, 3662779.835\n225.5,-3813480.284, 3554278.952, 3662780.514\n225.6,-3813479.963, 3554278.592, 3662781.193\n225.7,-3813479.637, 3554278.237, 3662781.873\n225.8,-3813479.306, 3554277.886, 3662782.553\n225.9,-3813478.970, 3554277.541, 3662783.233\n226.0,-3813478.630, 3554277.200, 3662783.913\n226.1,-3813478.285, 3554276.865, 3662784.593\n226.2,-3813477.935, 3554276.534, 3662785.274\n226.3,-3813477.580, 3554276.209, 3662785.954\n226.4,-3813477.221, 3554275.889, 3662786.634\n226.5,-3813476.857, 3554275.574, 3662787.315\n226.6,-3813476.488, 3554275.264, 3662787.995\n226.7,-3813476.115, 3554274.959, 3662788.674\n226.8,-3813475.737, 3554274.659, 3662789.354\n226.9,-3813475.354, 3554274.365, 3662790.033\n227.0,-3813474.967, 3554274.076, 3662790.712\n227.1,-3813474.576, 3554273.792, 3662791.391\n227.2,-3813474.180, 3554273.513, 3662792.069\n227.3,-3813473.779, 3554273.240, 3662792.747\n227.4,-3813473.374, 3554272.972, 3662793.424\n227.5,-3813472.965, 3554272.709, 3662794.101\n227.6,-3813472.551, 3554272.452, 3662794.777\n227.7,-3813472.133, 3554272.200, 3662795.452\n227.8,-3813471.710, 3554271.954, 3662796.127\n227.9,-3813471.283, 3554271.712, 3662796.800\n228.0,-3813470.852, 3554271.477, 3662797.473\n228.1,-3813470.417, 3554271.246, 3662798.146\n228.2,-3813469.977, 3554271.021, 3662798.817\n228.3,-3813469.533, 3554270.802, 3662799.487\n228.4,-3813469.086, 3554270.588, 3662800.157\n228.5,-3813468.634, 3554270.380, 3662800.825\n228.6,-3813468.178, 3554270.177, 3662801.492\n228.7,-3813467.717, 3554269.979, 3662802.159\n228.8,-3813467.253, 3554269.787, 3662802.823\n228.9,-3813466.785, 3554269.601, 3662803.487\n229.0,-3813466.313, 3554269.420, 3662804.150\n229.1,-3813465.837, 3554269.245, 3662804.811\n229.2,-3813465.357, 3554269.076, 3662805.471\n229.3,-3813464.873, 3554268.912, 3662806.129\n229.4,-3813464.386, 3554268.753, 3662806.786\n229.5,-3813463.894, 3554268.600, 3662807.441\n229.6,-3813463.399, 3554268.453, 3662808.095\n229.7,-3813462.900, 3554268.312, 3662808.748\n229.8,-3813462.398, 3554268.176, 3662809.398\n229.9,-3813461.891, 3554268.046, 3662810.047\n230.0,-3813461.381, 3554267.921, 3662810.695\n230.1,-3813460.868, 3554267.802, 3662811.340\n230.2,-3813460.351, 3554267.689, 3662811.984\n230.3,-3813459.830, 3554267.582, 3662812.626\n230.4,-3813459.307, 3554267.480, 3662813.266\n230.5,-3813458.779, 3554267.384, 3662813.904\n230.6,-3813458.248, 3554267.294, 3662814.540\n230.7,-3813457.714, 3554267.209, 3662815.174\n230.8,-3813457.177, 3554267.130, 3662815.806\n230.9,-3813456.636, 3554267.057, 3662816.435\n231.0,-3813456.092, 3554266.990, 3662817.063\n231.1,-3813455.544, 3554266.928, 3662817.688\n231.2,-3813454.994, 3554266.872, 3662818.312\n231.3,-3813454.440, 3554266.822, 3662818.932\n231.4,-3813453.884, 3554266.778, 3662819.551\n231.5,-3813453.324, 3554266.739, 3662820.167\n231.6,-3813452.761, 3554266.706, 3662820.781\n231.7,-3813452.195, 3554266.679, 3662821.392\n231.8,-3813451.627, 3554266.658, 3662822.001\n231.9,-3813451.055, 3554266.642, 3662822.607\n232.0,-3813450.480, 3554266.632, 3662823.210\n232.1,-3813449.903, 3554266.628, 3662823.811\n232.2,-3813449.323, 3554266.630, 3662824.410\n232.3,-3813448.740, 3554266.637, 3662825.005\n232.4,-3813448.155, 3554266.651, 3662825.598\n232.5,-3813447.566, 3554266.670, 3662826.188\n232.6,-3813446.976, 3554266.695, 3662826.775\n232.7,-3813446.382, 3554266.725, 3662827.359\n232.8,-3813445.786, 3554266.761, 3662827.941\n232.9,-3813445.188, 3554266.803, 3662828.519\n233.0,-3813444.587, 3554266.851, 3662829.094\n233.1,-3813443.983, 3554266.905, 3662829.667\n233.2,-3813443.378, 3554266.964, 3662830.236\n233.3,-3813442.770, 3554267.029, 3662830.802\n233.4,-3813442.159, 3554267.100, 3662831.365\n233.5,-3813441.547, 3554267.177, 3662831.925\n233.6,-3813440.932, 3554267.259, 3662832.481\n233.7,-3813440.315, 3554267.347, 3662833.034\n233.8,-3813439.696, 3554267.441, 3662833.584\n233.9,-3813439.075, 3554267.540, 3662834.131\n234.0,-3813438.451, 3554267.645, 3662834.674\n234.1,-3813437.826, 3554267.756, 3662835.213\n234.2,-3813437.199, 3554267.873, 3662835.750\n234.3,-3813436.570, 3554267.995, 3662836.282\n234.4,-3813435.939, 3554268.123, 3662836.812\n234.5,-3813435.306, 3554268.257, 3662837.337\n234.6,-3813434.672, 3554268.396, 3662837.859\n234.7,-3813434.036, 3554268.541, 3662838.377\n234.8,-3813433.398, 3554268.691, 3662838.892\n234.9,-3813432.758, 3554268.847, 3662839.403\n235.0,-3813432.117, 3554269.009, 3662839.910\n235.1,-3813431.474, 3554269.176, 3662840.413\n235.2,-3813430.830, 3554269.349, 3662840.913\n235.3,-3813430.184, 3554269.528, 3662841.409\n235.4,-3813429.537, 3554269.712, 3662841.900\n235.5,-3813428.889, 3554269.902, 3662842.388\n235.6,-3813428.239, 3554270.097, 3662842.872\n235.7,-3813427.588, 3554270.298, 3662843.352\n235.8,-3813426.936, 3554270.504, 3662843.828\n235.9,-3813426.282, 3554270.716, 3662844.299\n236.0,-3813425.627, 3554270.933, 3662844.767\n236.1,-3813424.972, 3554271.155, 3662845.231\n236.2,-3813424.315, 3554271.384, 3662845.690\n236.3,-3813423.657, 3554271.617, 3662846.145\n236.4,-3813422.998, 3554271.856, 3662846.596\n236.5,-3813422.338, 3554272.101, 3662847.043\n236.6,-3813421.678, 3554272.350, 3662847.485\n236.7,-3813421.016, 3554272.606, 3662847.923\n236.8,-3813420.354, 3554272.866, 3662848.357\n236.9,-3813419.691, 3554273.132, 3662848.786\n237.0,-3813419.028, 3554273.403, 3662849.211\n237.1,-3813418.364, 3554273.680, 3662849.631\n237.2,-3813417.699, 3554273.961, 3662850.047\n237.3,-3813417.033, 3554274.248, 3662850.459\n237.4,-3813416.367, 3554274.541, 3662850.866\n237.5,-3813415.701, 3554274.838, 3662851.268\n237.6,-3813415.034, 3554275.141, 3662851.666\n237.7,-3813414.367, 3554275.449, 3662852.059\n237.8,-3813413.700, 3554275.762, 3662852.447\n237.9,-3813413.032, 3554276.080, 3662852.831\n238.0,-3813412.364, 3554276.403, 3662853.211\n238.1,-3813411.696, 3554276.731, 3662853.585\n238.2,-3813411.028, 3554277.065, 3662853.955\n238.3,-3813410.359, 3554277.403, 3662854.320\n238.4,-3813409.691, 3554277.747, 3662854.680\n238.5,-3813409.022, 3554278.095, 3662855.035\n238.6,-3813408.354, 3554278.449, 3662855.386\n238.7,-3813407.686, 3554278.807, 3662855.731\n238.8,-3813407.018, 3554279.170, 3662856.072\n238.9,-3813406.350, 3554279.539, 3662856.408\n239.0,-3813405.682, 3554279.912, 3662856.739\n239.1,-3813405.015, 3554280.290, 3662857.064\n239.2,-3813404.348, 3554280.673, 3662857.385\n239.3,-3813403.681, 3554281.060, 3662857.701\n239.4,-3813403.015, 3554281.452, 3662858.012\n239.5,-3813402.349, 3554281.849, 3662858.318\n239.6,-3813401.684, 3554282.251, 3662858.619\n239.7,-3813401.019, 3554282.658, 3662858.914\n239.8,-3813400.355, 3554283.069, 3662859.205\n239.9,-3813399.691, 3554283.485, 3662859.490\n240.0,-3813399.029, 3554283.905, 3662859.770\n240.1,-3813398.367, 3554284.330, 3662860.045\n240.2,-3813397.706, 3554284.759, 3662860.315\n240.3,-3813397.045, 3554285.193, 3662860.580\n240.4,-3813396.386, 3554285.632, 3662860.839\n240.5,-3813395.727, 3554286.075, 3662861.093\n240.6,-3813395.070, 3554286.522, 3662861.342\n240.7,-3813394.413, 3554286.974, 3662861.586\n240.8,-3813393.757, 3554287.430, 3662861.824\n240.9,-3813393.103, 3554287.890, 3662862.057\n241.0,-3813392.450, 3554288.355, 3662862.285\n241.1,-3813391.798, 3554288.824, 3662862.507\n241.2,-3813391.147, 3554289.297, 3662862.724\n241.3,-3813390.498, 3554289.774, 3662862.936\n241.4,-3813389.849, 3554290.256, 3662863.142\n241.5,-3813389.203, 3554290.741, 3662863.342\n241.6,-3813388.557, 3554291.231, 3662863.538\n241.7,-3813387.913, 3554291.725, 3662863.728\n241.8,-3813387.271, 3554292.223, 3662863.912\n241.9,-3813386.630, 3554292.724, 3662864.091\n242.0,-3813385.991, 3554293.230, 3662864.264\n242.1,-3813385.354, 3554293.740, 3662864.432\n242.2,-3813384.718, 3554294.253, 3662864.595\n242.3,-3813384.084, 3554294.771, 3662864.752\n242.4,-3813383.451, 3554295.292, 3662864.903\n242.5,-3813382.821, 3554295.817, 3662865.049\n242.6,-3813382.192, 3554296.346, 3662865.190\n242.7,-3813381.566, 3554296.878, 3662865.325\n242.8,-3813380.941, 3554297.414, 3662865.454\n242.9,-3813380.318, 3554297.954, 3662865.578\n243.0,-3813379.698, 3554298.498, 3662865.696\n243.1,-3813379.079, 3554299.045, 3662865.808\n243.2,-3813378.463, 3554299.595, 3662865.915\n243.3,-3813377.848, 3554300.149, 3662866.017\n243.4,-3813377.236, 3554300.706, 3662866.112\n243.5,-3813376.626, 3554301.267, 3662866.202\n243.6,-3813376.019, 3554301.831, 3662866.287\n243.7,-3813375.414, 3554302.399, 3662866.366\n243.8,-3813374.811, 3554302.969, 3662866.439\n243.9,-3813374.211, 3554303.543, 3662866.507\n244.0,-3813373.613, 3554304.121, 3662866.569\n244.1,-3813373.017, 3554304.701, 3662866.625\n244.2,-3813372.425, 3554305.284, 3662866.675\n244.3,-3813371.834, 3554305.871, 3662866.720\n244.4,-3813371.247, 3554306.460, 3662866.760\n244.5,-3813370.662, 3554307.053, 3662866.793\n244.6,-3813370.080, 3554307.649, 3662866.822\n244.7,-3813369.500, 3554308.247, 3662866.844\n244.8,-3813368.924, 3554308.849, 3662866.861\n244.9,-3813368.350, 3554309.453, 3662866.872\n245.0,-3813367.779, 3554310.060, 3662866.877\n245.1,-3813367.211, 3554310.669, 3662866.877\n245.2,-3813366.646, 3554311.282, 3662866.871\n245.3,-3813366.084, 3554311.897, 3662866.859\n245.4,-3813365.525, 3554312.515, 3662866.842\n245.5,-3813364.969, 3554313.135, 3662866.819\n245.6,-3813364.416, 3554313.758, 3662866.790\n245.7,-3813363.866, 3554314.383, 3662866.756\n245.8,-3813363.320, 3554315.011, 3662866.716\n245.9,-3813362.776, 3554315.642, 3662866.670\n246.0,-3813362.236, 3554316.274, 3662866.619\n246.1,-3813361.700, 3554316.909, 3662866.562\n246.2,-3813361.166, 3554317.546, 3662866.499\n246.3,-3813360.636, 3554318.186, 3662866.431\n246.4,-3813360.110, 3554318.827, 3662866.357\n246.5,-3813359.586, 3554319.471, 3662866.277\n246.6,-3813359.067, 3554320.117, 3662866.192\n246.7,-3813358.551, 3554320.765, 3662866.102\n246.8,-3813358.038, 3554321.415, 3662866.005\n246.9,-3813357.529, 3554322.067, 3662865.903\n247.0,-3813357.024, 3554322.721, 3662865.796\n247.1,-3813356.522, 3554323.376, 3662865.682\n247.2,-3813356.024, 3554324.034, 3662865.564\n247.3,-3813355.530, 3554324.693, 3662865.439\n247.4,-3813355.039, 3554325.354, 3662865.309\n247.5,-3813354.553, 3554326.017, 3662865.174\n247.6,-3813354.070, 3554326.681, 3662865.033\n247.7,-3813353.591, 3554327.347, 3662864.886\n247.8,-3813353.116, 3554328.015, 3662864.734\n247.9,-3813352.644, 3554328.684, 3662864.576\n248.0,-3813352.177, 3554329.354, 3662864.413\n248.1,-3813351.714, 3554330.026, 3662864.245\n248.2,-3813351.255, 3554330.699, 3662864.071\n248.3,-3813350.800, 3554331.374, 3662863.891\n248.4,-3813350.349, 3554332.050, 3662863.706\n248.5,-3813349.902, 3554332.727, 3662863.515\n248.6,-3813349.459, 3554333.405, 3662863.320\n248.7,-3813349.021, 3554334.085, 3662863.118\n248.8,-3813348.586, 3554334.765, 3662862.911\n248.9,-3813348.156, 3554335.447, 3662862.699\n249.0,-3813347.731, 3554336.129, 3662862.482\n249.1,-3813347.309, 3554336.813, 3662862.259\n249.2,-3813346.892, 3554337.497, 3662862.030\n249.3,-3813346.479, 3554338.182, 3662861.797\n249.4,-3813346.071, 3554338.868, 3662861.558\n249.5,-3813345.667, 3554339.555, 3662861.314\n249.6,-3813345.267, 3554340.242, 3662861.064\n249.7,-3813344.872, 3554340.930, 3662860.810\n249.8,-3813344.482, 3554341.619, 3662860.550\n249.9,-3813344.096, 3554342.308, 3662860.284\n250.0,-3813343.714, 3554342.998, 3662860.014\n250.1,-3813343.338, 3554343.688, 3662859.738\n250.2,-3813342.965, 3554344.379, 3662859.457\n250.3,-3813342.598, 3554345.070, 3662859.171\n250.4,-3813342.235, 3554345.762, 3662858.880\n250.5,-3813341.877, 3554346.453, 3662858.584\n250.6,-3813341.523, 3554347.145, 3662858.283\n250.7,-3813341.174, 3554347.837, 3662857.976\n250.8,-3813340.830, 3554348.529, 3662857.665\n250.9,-3813340.491, 3554349.222, 3662857.349\n251.0,-3813340.157, 3554349.914, 3662857.027\n251.1,-3813339.827, 3554350.606, 3662856.701\n251.2,-3813339.502, 3554351.298, 3662856.369\n251.3,-3813339.183, 3554351.990, 3662856.033\n251.4,-3813338.868, 3554352.682, 3662855.692\n251.5,-3813338.558, 3554353.374, 3662855.345\n251.6,-3813338.253, 3554354.066, 3662854.994\n251.7,-3813337.952, 3554354.757, 3662854.638\n251.8,-3813337.657, 3554355.448, 3662854.278\n251.9,-3813337.367, 3554356.138, 3662853.912\n252.0,-3813337.082, 3554356.828, 3662853.542\n252.1,-3813336.802, 3554357.518, 3662853.167\n252.2,-3813336.527, 3554358.206, 3662852.787\n252.3,-3813336.257, 3554358.895, 3662852.403\n252.4,-3813335.992, 3554359.583, 3662852.014\n252.5,-3813335.733, 3554360.270, 3662851.620\n252.6,-3813335.478, 3554360.956, 3662851.222\n252.7,-3813335.229, 3554361.641, 3662850.819\n252.8,-3813334.985, 3554362.326, 3662850.411\n252.9,-3813334.746, 3554363.010, 3662849.999\n253.0,-3813334.512, 3554363.693, 3662849.583\n253.1,-3813334.284, 3554364.375, 3662849.162\n253.2,-3813334.060, 3554365.056, 3662848.737\n253.3,-3813333.842, 3554365.735, 3662848.307\n253.4,-3813333.629, 3554366.414, 3662847.873\n253.5,-3813333.422, 3554367.092, 3662847.434\n253.6,-3813333.220, 3554367.768, 3662846.991\n253.7,-3813333.023, 3554368.443, 3662846.544\n253.8,-3813332.831, 3554369.117, 3662846.093\n253.9,-3813332.645, 3554369.789, 3662845.637\n254.0,-3813332.464, 3554370.460, 3662845.177\n254.1,-3813332.289, 3554371.130, 3662844.713\n254.2,-3813332.119, 3554371.798, 3662844.245\n254.3,-3813331.954, 3554372.465, 3662843.773\n254.4,-3813331.795, 3554373.130, 3662843.297\n254.5,-3813331.641, 3554373.793, 3662842.816\n254.6,-3813331.493, 3554374.455, 3662842.332\n254.7,-3813331.350, 3554375.115, 3662841.844\n254.8,-3813331.212, 3554375.773, 3662841.352\n254.9,-3813331.080, 3554376.429, 3662840.855\n255.0,-3813330.953, 3554377.084, 3662840.356\n255.1,-3813330.832, 3554377.737, 3662839.852\n255.2,-3813330.716, 3554378.387, 3662839.344\n255.3,-3813330.606, 3554379.036, 3662838.833\n255.4,-3813330.501, 3554379.683, 3662838.318\n255.5,-3813330.402, 3554380.327, 3662837.799\n255.6,-3813330.309, 3554380.970, 3662837.277\n255.7,-3813330.220, 3554381.610, 3662836.751\n255.8,-3813330.138, 3554382.248, 3662836.221\n255.9,-3813330.061, 3554382.884, 3662835.688\n256.0,-3813329.989, 3554383.518, 3662835.151\n256.1,-3813329.923, 3554384.149, 3662834.611\n256.2,-3813329.863, 3554384.777, 3662834.068\n256.3,-3813329.808, 3554385.404, 3662833.521\n256.4,-3813329.758, 3554386.028, 3662832.970\n256.5,-3813329.714, 3554386.649, 3662832.417\n256.6,-3813329.676, 3554387.268, 3662831.860\n256.7,-3813329.643, 3554387.884, 3662831.300\n256.8,-3813329.616, 3554388.498, 3662830.737\n256.9,-3813329.595, 3554389.108, 3662830.170\n257.0,-3813329.579, 3554389.716, 3662829.601\n257.1,-3813329.568, 3554390.322, 3662829.028\n257.2,-3813329.563, 3554390.924, 3662828.452\n257.3,-3813329.564, 3554391.524, 3662827.874\n257.4,-3813329.570, 3554392.121, 3662827.292\n257.5,-3813329.582, 3554392.714, 3662826.707\n257.6,-3813329.600, 3554393.305, 3662826.120\n257.7,-3813329.623, 3554393.893, 3662825.530\n257.8,-3813329.651, 3554394.478, 3662824.936\n257.9,-3813329.685, 3554395.059, 3662824.341\n258.0,-3813329.725, 3554395.638, 3662823.742\n258.1,-3813329.770, 3554396.213, 3662823.141\n258.2,-3813329.821, 3554396.785, 3662822.537\n258.3,-3813329.877, 3554397.354, 3662821.930\n258.4,-3813329.939, 3554397.919, 3662821.321\n258.5,-3813330.006, 3554398.481, 3662820.710\n258.6,-3813330.079, 3554399.040, 3662820.096\n258.7,-3813330.158, 3554399.595, 3662819.480\n258.8,-3813330.242, 3554400.147, 3662818.861\n258.9,-3813330.331, 3554400.695, 3662818.240\n259.0,-3813330.427, 3554401.240, 3662817.616\n259.1,-3813330.527, 3554401.781, 3662816.991\n259.2,-3813330.633, 3554402.319, 3662816.363\n259.3,-3813330.745, 3554402.853, 3662815.733\n259.4,-3813330.862, 3554403.383, 3662815.101\n259.5,-3813330.984, 3554403.909, 3662814.466\n259.6,-3813331.112, 3554404.432, 3662813.830\n259.7,-3813331.246, 3554404.951, 3662813.192\n259.8,-3813331.385, 3554405.466, 3662812.552\n259.9,-3813331.529, 3554405.977, 3662811.910\n260.0,-3813331.679, 3554406.485, 3662811.266\n260.1,-3813331.834, 3554406.988, 3662810.620\n260.2,-3813331.995, 3554407.487, 3662809.973\n260.3,-3813332.161, 3554407.983, 3662809.323\n260.4,-3813332.332, 3554408.474, 3662808.672\n260.5,-3813332.509, 3554408.961, 3662808.020\n260.6,-3813332.691, 3554409.444, 3662807.366\n260.7,-3813332.879, 3554409.923, 3662806.710\n260.8,-3813333.072, 3554410.398, 3662806.053\n260.9,-3813333.270, 3554410.869, 3662805.395\n261.0,-3813333.473, 3554411.335, 3662804.735\n261.1,-3813333.682, 3554411.797, 3662804.073\n261.2,-3813333.896, 3554412.255, 3662803.411\n261.3,-3813334.116, 3554412.708, 3662802.747\n261.4,-3813334.340, 3554413.157, 3662802.082\n261.5,-3813334.570, 3554413.602, 3662801.415\n261.6,-3813334.805, 3554414.042, 3662800.748\n261.7,-3813335.045, 3554414.478, 3662800.080\n261.8,-3813335.291, 3554414.909, 3662799.410\n261.9,-3813335.542, 3554415.336, 3662798.740\n262.0,-3813335.797, 3554415.758, 3662798.068\n262.1,-3813336.058, 3554416.176, 3662797.396\n262.2,-3813336.324, 3554416.589, 3662796.723\n262.3,-3813336.595, 3554416.997, 3662796.049\n262.4,-3813336.872, 3554417.400, 3662795.374\n262.5,-3813337.153, 3554417.799, 3662794.699\n262.6,-3813337.439, 3554418.194, 3662794.022\n262.7,-3813337.731, 3554418.583, 3662793.346\n262.8,-3813338.027, 3554418.968, 3662792.669\n262.9,-3813338.328, 3554419.347, 3662791.991\n263.0,-3813338.635, 3554419.722, 3662791.313\n263.1,-3813338.946, 3554420.093, 3662790.634\n263.2,-3813339.262, 3554420.458, 3662789.955\n263.3,-3813339.583, 3554420.818, 3662789.276\n263.4,-3813339.909, 3554421.174, 3662788.596\n263.5,-3813340.240, 3554421.524, 3662787.916\n263.6,-3813340.575, 3554421.869, 3662787.236\n263.7,-3813340.916, 3554422.210, 3662786.556\n263.8,-3813341.261, 3554422.545, 3662785.876\n263.9,-3813341.611, 3554422.876, 3662785.195\n264.0,-3813341.966, 3554423.201, 3662784.515\n264.1,-3813342.325, 3554423.521, 3662783.835\n264.2,-3813342.689, 3554423.836, 3662783.154\n264.3,-3813343.058, 3554424.146, 3662782.474\n264.4,-3813343.431, 3554424.451, 3662781.795\n264.5,-3813343.809, 3554424.750, 3662781.115\n264.6,-3813344.192, 3554425.044, 3662780.436\n264.7,-3813344.579, 3554425.334, 3662779.757\n264.8,-3813344.971, 3554425.617, 3662779.078\n264.9,-3813345.367, 3554425.896, 3662778.400\n265.0,-3813345.767, 3554426.169, 3662777.722\n265.1,-3813346.172, 3554426.437, 3662777.045\n265.2,-3813346.582, 3554426.700, 3662776.368\n265.3,-3813346.996, 3554426.957, 3662775.692\n265.4,-3813347.414, 3554427.209, 3662775.017\n265.5,-3813347.837, 3554427.456, 3662774.342\n265.6,-3813348.263, 3554427.697, 3662773.669\n265.7,-3813348.695, 3554427.932, 3662772.996\n265.8,-3813349.130, 3554428.163, 3662772.323\n265.9,-3813349.570, 3554428.387, 3662771.652\n266.0,-3813350.013, 3554428.607, 3662770.982\n266.1,-3813350.461, 3554428.821, 3662770.312\n266.2,-3813350.913, 3554429.029, 3662769.644\n266.3,-3813351.369, 3554429.232, 3662768.977\n266.4,-3813351.830, 3554429.429, 3662768.311\n266.5,-3813352.294, 3554429.621, 3662767.646\n266.6,-3813352.762, 3554429.807, 3662766.982\n266.7,-3813353.234, 3554429.988, 3662766.319\n266.8,-3813353.710, 3554430.163, 3662765.658\n266.9,-3813354.190, 3554430.333, 3662764.998\n267.0,-3813354.674, 3554430.497, 3662764.340\n267.1,-3813355.162, 3554430.655, 3662763.683\n267.2,-3813355.653, 3554430.808, 3662763.028\n267.3,-3813356.148, 3554430.955, 3662762.374\n267.4,-3813356.647, 3554431.096, 3662761.721\n267.5,-3813357.150, 3554431.232, 3662761.071\n267.6,-3813357.656, 3554431.362, 3662760.422\n267.7,-3813358.166, 3554431.487, 3662759.775\n267.8,-3813358.679, 3554431.606, 3662759.129\n267.9,-3813359.196, 3554431.719, 3662758.485\n268.0,-3813359.717, 3554431.826, 3662757.844\n268.1,-3813360.241, 3554431.928, 3662757.204\n268.2,-3813360.768, 3554432.024, 3662756.566\n268.3,-3813361.299, 3554432.114, 3662755.930\n268.4,-3813361.834, 3554432.199, 3662755.296\n268.5,-3813362.371, 3554432.277, 3662754.664\n268.6,-3813362.912, 3554432.350, 3662754.034\n268.7,-3813363.456, 3554432.418, 3662753.406\n268.8,-3813364.003, 3554432.479, 3662752.781\n268.9,-3813364.554, 3554432.535, 3662752.158\n269.0,-3813365.107, 3554432.585, 3662751.537\n269.1,-3813365.664, 3554432.630, 3662750.919\n269.2,-3813366.224, 3554432.668, 3662750.303\n269.3,-3813366.787, 3554432.701, 3662749.689\n269.4,-3813367.353, 3554432.728, 3662749.078\n269.5,-3813367.921, 3554432.749, 3662748.469\n269.6,-3813368.493, 3554432.765, 3662747.863\n269.7,-3813369.067, 3554432.775, 3662747.259\n269.8,-3813369.645, 3554432.779, 3662746.658\n269.9,-3813370.225, 3554432.777, 3662746.060\n270.0,-3813370.808, 3554432.769, 3662745.465\n270.1,-3813371.393, 3554432.756, 3662744.872\n270.2,-3813371.982, 3554432.737, 3662744.282\n270.3,-3813372.573, 3554432.712, 3662743.695\n270.4,-3813373.166, 3554432.682, 3662743.111\n270.5,-3813373.762, 3554432.645, 3662742.529\n270.6,-3813374.361, 3554432.603, 3662741.951\n270.7,-3813374.961, 3554432.555, 3662741.376\n270.8,-3813375.565, 3554432.502, 3662740.803\n270.9,-3813376.171, 3554432.442, 3662740.234\n271.0,-3813376.779, 3554432.377, 3662739.668\n271.1,-3813377.389, 3554432.306, 3662739.105\n271.2,-3813378.002, 3554432.229, 3662738.545\n271.3,-3813378.617, 3554432.147, 3662737.989\n271.4,-3813379.234, 3554432.059, 3662737.436\n271.5,-3813379.853, 3554431.965, 3662736.886\n271.6,-3813380.474, 3554431.866, 3662736.340\n271.7,-3813381.097, 3554431.761, 3662735.796\n271.8,-3813381.722, 3554431.650, 3662735.257\n271.9,-3813382.349, 3554431.533, 3662734.721\n272.0,-3813382.979, 3554431.411, 3662734.188\n272.1,-3813383.609, 3554431.283, 3662733.659\n272.2,-3813384.242, 3554431.149, 3662733.133\n272.3,-3813384.877, 3554431.010, 3662732.611\n272.4,-3813385.513, 3554430.865, 3662732.093\n272.5,-3813386.151, 3554430.714, 3662731.578\n272.6,-3813386.790, 3554430.558, 3662731.067\n272.7,-3813387.432, 3554430.396, 3662730.560\n272.8,-3813388.074, 3554430.229, 3662730.057\n272.9,-3813388.719, 3554430.056, 3662729.558\n273.0,-3813389.364, 3554429.877, 3662729.062\n273.1,-3813390.011, 3554429.693, 3662728.570\n273.2,-3813390.660, 3554429.504, 3662728.082\n273.3,-3813391.310, 3554429.308, 3662727.599\n273.4,-3813391.961, 3554429.108, 3662727.119\n273.5,-3813392.613, 3554428.901, 3662726.643\n273.6,-3813393.267, 3554428.689, 3662726.171\n273.7,-3813393.921, 3554428.472, 3662725.704\n273.8,-3813394.577, 3554428.249, 3662725.240\n273.9,-3813395.234, 3554428.021, 3662724.781\n274.0,-3813395.892, 3554427.788, 3662724.326\n274.1,-3813396.551, 3554427.549, 3662723.875\n274.2,-3813397.210, 3554427.304, 3662723.428\n274.3,-3813397.871, 3554427.054, 3662722.986\n274.4,-3813398.532, 3554426.799, 3662722.548\n274.5,-3813399.194, 3554426.538, 3662722.115\n274.6,-3813399.857, 3554426.273, 3662721.685\n274.7,-3813400.521, 3554426.001, 3662721.260\n274.8,-3813401.185, 3554425.725, 3662720.840\n274.9,-3813401.850, 3554425.443, 3662720.424\n275.0,-3813402.515, 3554425.156, 3662720.013\n275.1,-3813403.181, 3554424.864, 3662719.606\n275.2,-3813403.848, 3554424.566, 3662719.203\n275.3,-3813404.515, 3554424.263, 3662718.806\n275.4,-3813405.182, 3554423.955, 3662718.413\n275.5,-3813405.849, 3554423.642, 3662718.024\n275.6,-3813406.517, 3554423.324, 3662717.640\n275.7,-3813407.185, 3554423.001, 3662717.261\n275.8,-3813407.853, 3554422.673, 3662716.887\n275.9,-3813408.521, 3554422.339, 3662716.517\n276.0,-3813409.190, 3554422.001, 3662716.152\n276.1,-3813409.858, 3554421.657, 3662715.792\n276.2,-3813410.526, 3554421.309, 3662715.437\n276.3,-3813411.195, 3554420.955, 3662715.086\n276.4,-3813411.863, 3554420.597, 3662714.741\n276.5,-3813412.531, 3554420.233, 3662714.400\n276.6,-3813413.199, 3554419.865, 3662714.064\n276.7,-3813413.867, 3554419.492, 3662713.734\n276.8,-3813414.534, 3554419.114, 3662713.408\n276.9,-3813415.201, 3554418.731, 3662713.087\n277.0,-3813415.868, 3554418.343, 3662712.771\n277.1,-3813416.534, 3554417.951, 3662712.460\n277.2,-3813417.200, 3554417.554, 3662712.154\n277.3,-3813417.865, 3554417.152, 3662711.854\n277.4,-3813418.530, 3554416.746, 3662711.558\n277.5,-3813419.194, 3554416.334, 3662711.268\n277.6,-3813419.857, 3554415.919, 3662710.982\n277.7,-3813420.520, 3554415.498, 3662710.702\n277.8,-3813421.182, 3554415.073, 3662710.427\n277.9,-3813421.843, 3554414.644, 3662710.157\n278.0,-3813422.504, 3554414.210, 3662709.893\n278.1,-3813423.163, 3554413.771, 3662709.633\n278.2,-3813423.822, 3554413.328, 3662709.379\n278.3,-3813424.479, 3554412.881, 3662709.131\n278.4,-3813425.136, 3554412.429, 3662708.887\n278.5,-3813425.791, 3554411.973, 3662708.649\n278.6,-3813426.446, 3554411.513, 3662708.416\n278.7,-3813427.099, 3554411.048, 3662708.188\n278.8,-3813427.751, 3554410.579, 3662707.966\n278.9,-3813428.402, 3554410.106, 3662707.749\n279.0,-3813429.051, 3554409.629, 3662707.538\n279.1,-3813429.699, 3554409.147, 3662707.331\n279.2,-3813430.346, 3554408.661, 3662707.131\n279.3,-3813430.991, 3554408.172, 3662706.936\n279.4,-3813431.635, 3554407.678, 3662706.746\n279.5,-3813432.277, 3554407.180, 3662706.561\n279.6,-3813432.918, 3554406.678, 3662706.382\n279.7,-3813433.557, 3554406.172, 3662706.209\n279.8,-3813434.195, 3554405.663, 3662706.041\n279.9,-3813434.831, 3554405.149, 3662705.879\n280.0,-3813435.465, 3554404.631, 3662705.722\n280.1,-3813436.097, 3554404.110, 3662705.570\n280.2,-3813436.727, 3554403.585, 3662705.424\n280.3,-3813437.356, 3554403.056, 3662705.284\n280.4,-3813437.983, 3554402.524, 3662705.149\n280.5,-3813438.607, 3554401.988, 3662705.020\n280.6,-3813439.230, 3554401.448, 3662704.896\n280.7,-3813439.851, 3554400.904, 3662704.778\n280.8,-3813440.469, 3554400.358, 3662704.666\n280.9,-3813441.086, 3554399.807, 3662704.559\n281.0,-3813441.700, 3554399.253, 3662704.458\n281.1,-3813442.312, 3554398.696, 3662704.362\n281.2,-3813442.922, 3554398.135, 3662704.272\n281.3,-3813443.529, 3554397.571, 3662704.187\n281.4,-3813444.134, 3554397.003, 3662704.109\n281.5,-3813444.737, 3554396.433, 3662704.035\n281.6,-3813445.338, 3554395.859, 3662703.968\n281.7,-3813445.935, 3554395.281, 3662703.906\n281.8,-3813446.531, 3554394.701, 3662703.850\n281.9,-3813447.124, 3554394.117, 3662703.799\n282.0,-3813447.714, 3554393.531, 3662703.754\n282.1,-3813448.301, 3554392.941, 3662703.715\n282.2,-3813448.886, 3554392.349, 3662703.681\n282.3,-3813449.468, 3554391.753, 3662703.653\n282.4,-3813450.048, 3554391.154, 3662703.631\n282.5,-3813450.624, 3554390.553, 3662703.614\n282.6,-3813451.198, 3554389.949, 3662703.603\n282.7,-3813451.769, 3554389.342, 3662703.598\n282.8,-3813452.337, 3554388.732, 3662703.598\n282.9,-3813452.902, 3554388.120, 3662703.604\n283.0,-3813453.464, 3554387.504, 3662703.616\n283.1,-3813454.023, 3554386.887, 3662703.634\n283.2,-3813454.579, 3554386.266, 3662703.657\n283.3,-3813455.132, 3554385.643, 3662703.685\n283.4,-3813455.682, 3554385.018, 3662703.720\n283.5,-3813456.228, 3554384.390, 3662703.760\n283.6,-3813456.771, 3554383.760, 3662703.805\n283.7,-3813457.311, 3554383.127, 3662703.857\n283.8,-3813457.848, 3554382.492, 3662703.914\n283.9,-3813458.381, 3554381.855, 3662703.976\n284.0,-3813458.911, 3554381.216, 3662704.045\n284.1,-3813459.438, 3554380.574, 3662704.119\n284.2,-3813459.961, 3554379.930, 3662704.198\n284.3,-3813460.481, 3554379.284, 3662704.283\n284.4,-3813460.997, 3554378.636, 3662704.374\n284.5,-3813461.509, 3554377.986, 3662704.471\n284.6,-3813462.018, 3554377.334, 3662704.573\n284.7,-3813462.524, 3554376.681, 3662704.680\n284.8,-3813463.025, 3554376.025, 3662704.794\n284.9,-3813463.523, 3554375.367, 3662704.912\n285.0,-3813464.017, 3554374.708, 3662705.037\n285.1,-3813464.508, 3554374.047, 3662705.167\n285.2,-3813464.995, 3554373.384, 3662705.302\n285.3,-3813465.477, 3554372.720, 3662705.443\n285.4,-3813465.956, 3554372.054, 3662705.590\n285.5,-3813466.431, 3554371.386, 3662705.742\n285.6,-3813466.903, 3554370.717, 3662705.900\n285.7,-3813467.370, 3554370.047, 3662706.063\n285.8,-3813467.833, 3554369.375, 3662706.232\n285.9,-3813468.292, 3554368.702, 3662706.406\n286.0,-3813468.747, 3554368.027, 3662706.586\n286.1,-3813469.198, 3554367.351, 3662706.771\n286.2,-3813469.645, 3554366.674, 3662706.961\n286.3,-3813470.088, 3554365.996, 3662707.157\n286.4,-3813470.526, 3554365.316, 3662707.359\n286.5,-3813470.960, 3554364.636, 3662707.565\n286.6,-3813471.390, 3554363.954, 3662707.778\n286.7,-3813471.816, 3554363.272, 3662707.995\n286.8,-3813472.238, 3554362.588, 3662708.218\n286.9,-3813472.655, 3554361.904, 3662708.447\n287.0,-3813473.067, 3554361.219, 3662708.680\n287.1,-3813473.476, 3554360.533, 3662708.919\n287.2,-3813473.880, 3554359.846, 3662709.163\n287.3,-3813474.279, 3554359.159, 3662709.413\n287.4,-3813474.674, 3554358.470, 3662709.668\n287.5,-3813475.065, 3554357.782, 3662709.928\n287.6,-3813475.450, 3554357.092, 3662710.193\n287.7,-3813475.832, 3554356.403, 3662710.464\n287.8,-3813476.209, 3554355.712, 3662710.739\n287.9,-3813476.581, 3554355.022, 3662711.020\n288.0,-3813476.948, 3554354.331, 3662711.306\n288.1,-3813477.311, 3554353.639, 3662711.597\n288.2,-3813477.669, 3554352.948, 3662711.894\n288.3,-3813478.023, 3554352.256, 3662712.195\n288.4,-3813478.372, 3554351.564, 3662712.501\n288.5,-3813478.716, 3554350.872, 3662712.813\n288.6,-3813479.055, 3554350.179, 3662713.129\n288.7,-3813479.389, 3554349.487, 3662713.451\n288.8,-3813479.719, 3554348.795, 3662713.777\n288.9,-3813480.043, 3554348.102, 3662714.109\n289.0,-3813480.363, 3554347.410, 3662714.445\n289.1,-3813480.678, 3554346.718, 3662714.786\n289.2,-3813480.988, 3554346.027, 3662715.133\n289.3,-3813481.293, 3554345.335, 3662715.484\n289.4,-3813481.593, 3554344.644, 3662715.840\n289.5,-3813481.888, 3554343.953, 3662716.200\n289.6,-3813482.178, 3554343.263, 3662716.566\n289.7,-3813482.463, 3554342.573, 3662716.936\n289.8,-3813482.743, 3554341.883, 3662717.311\n289.9,-3813483.018, 3554341.194, 3662717.691\n290.0,-3813483.288, 3554340.506, 3662718.076\n290.1,-3813483.553, 3554339.818, 3662718.465\n290.2,-3813483.812, 3554339.131, 3662718.858\n290.3,-3813484.067, 3554338.445, 3662719.257\n290.4,-3813484.316, 3554337.759, 3662719.660\n290.5,-3813484.560, 3554337.075, 3662720.067\n290.6,-3813484.799, 3554336.391, 3662720.479\n290.7,-3813485.033, 3554335.708, 3662720.896\n290.8,-3813485.261, 3554335.026, 3662721.317\n290.9,-3813485.485, 3554334.345, 3662721.742\n291.0,-3813485.703, 3554333.666, 3662722.172\n291.1,-3813485.915, 3554332.987, 3662722.606\n291.2,-3813486.123, 3554332.309, 3662723.045\n291.3,-3813486.325, 3554331.633, 3662723.488\n291.4,-3813486.522, 3554330.958, 3662723.935\n291.5,-3813486.713, 3554330.284, 3662724.386\n291.6,-3813486.899, 3554329.612, 3662724.842\n291.7,-3813487.080, 3554328.941, 3662725.302\n291.8,-3813487.255, 3554328.271, 3662725.766\n291.9,-3813487.425, 3554327.603, 3662726.234\n292.0,-3813487.590, 3554326.936, 3662726.706\n292.1,-3813487.749, 3554326.271, 3662727.183\n292.2,-3813487.903, 3554325.608, 3662727.663\n292.3,-3813488.052, 3554324.946, 3662728.147\n292.4,-3813488.195, 3554324.286, 3662728.636\n292.5,-3813488.332, 3554323.628, 3662729.128\n292.6,-3813488.464, 3554322.972, 3662729.624\n292.7,-3813488.591, 3554322.317, 3662730.124\n292.8,-3813488.712, 3554321.665, 3662730.628\n292.9,-3813488.827, 3554321.014, 3662731.135\n293.0,-3813488.938, 3554320.365, 3662731.647\n293.1,-3813489.042, 3554319.718, 3662732.162\n293.2,-3813489.141, 3554319.074, 3662732.681\n293.3,-3813489.235, 3554318.431, 3662733.203\n293.4,-3813489.323, 3554317.791, 3662733.729\n293.5,-3813489.406, 3554317.153, 3662734.259\n293.6,-3813489.483, 3554316.517, 3662734.792\n293.7,-3813489.554, 3554315.884, 3662735.328\n293.8,-3813489.620, 3554315.253, 3662735.869\n293.9,-3813489.681, 3554314.624, 3662736.412\n294.0,-3813489.736, 3554313.998, 3662736.959\n294.1,-3813489.785, 3554313.374, 3662737.509\n294.2,-3813489.829, 3554312.752, 3662738.063\n294.3,-3813489.867, 3554312.134, 3662738.620\n294.4,-3813489.900, 3554311.517, 3662739.180\n294.5,-3813489.927, 3554310.904, 3662739.743\n294.6,-3813489.948, 3554310.293, 3662740.310\n294.7,-3813489.964, 3554309.685, 3662740.879\n294.8,-3813489.975, 3554309.080, 3662741.452\n294.9,-3813489.979, 3554308.477, 3662742.028\n295.0,-3813489.979, 3554307.878, 3662742.607\n295.1,-3813489.972, 3554307.281, 3662743.188\n295.2,-3813489.961, 3554306.687, 3662743.773\n295.3,-3813489.943, 3554306.097, 3662744.360\n295.4,-3813489.920, 3554305.509, 3662744.951\n295.5,-3813489.891, 3554304.924, 3662745.544\n295.6,-3813489.857, 3554304.343, 3662746.140\n295.7,-3813489.818, 3554303.764, 3662746.738\n295.8,-3813489.772, 3554303.189, 3662747.339\n295.9,-3813489.722, 3554302.617, 3662747.943\n296.0,-3813489.665, 3554302.048, 3662748.550\n296.1,-3813489.603, 3554301.483, 3662749.159\n296.2,-3813489.536, 3554300.921, 3662749.770\n296.3,-3813489.463, 3554300.362, 3662750.384\n296.4,-3813489.384, 3554299.807, 3662751.001\n296.5,-3813489.300, 3554299.255, 3662751.620\n296.6,-3813489.211, 3554298.707, 3662752.241\n296.7,-3813489.115, 3554298.162, 3662752.864\n296.8,-3813489.015, 3554297.621, 3662753.490\n296.9,-3813488.909, 3554297.083, 3662754.118\n297.0,-3813488.797, 3554296.550, 3662754.748\n297.1,-3813488.680, 3554296.019, 3662755.380\n297.2,-3813488.557, 3554295.493, 3662756.014\n297.3,-3813488.429, 3554294.970, 3662756.650\n297.4,-3813488.296, 3554294.451, 3662757.289\n297.5,-3813488.157, 3554293.936, 3662757.929\n297.6,-3813488.012, 3554293.425, 3662758.571\n297.7,-3813487.863, 3554292.918, 3662759.215\n297.8,-3813487.707, 3554292.415, 3662759.861\n297.9,-3813487.547, 3554291.915, 3662760.508\n298.0,-3813487.380, 3554291.420, 3662761.157\n298.1,-3813487.209, 3554290.929, 3662761.808\n298.2,-3813487.032, 3554290.441, 3662762.461\n298.3,-3813486.850, 3554289.958, 3662763.115\n298.4,-3813486.662, 3554289.479, 3662763.771\n298.5,-3813486.469, 3554289.004, 3662764.428\n298.6,-3813486.271, 3554288.534, 3662765.086\n298.7,-3813486.068, 3554288.068, 3662765.746\n298.8,-3813485.859, 3554287.606, 3662766.408\n298.9,-3813485.645, 3554287.148, 3662767.070\n299.0,-3813485.425, 3554286.695, 3662767.734\n299.1,-3813485.201, 3554286.246, 3662768.399\n299.2,-3813484.971, 3554285.801, 3662769.066\n299.3,-3813484.736, 3554285.361, 3662769.733\n299.4,-3813484.495, 3554284.925, 3662770.401\n299.5,-3813484.250, 3554284.494, 3662771.071\n299.6,-3813483.999, 3554284.067, 3662771.741\n299.7,-3813483.743, 3554283.645, 3662772.413\n299.8,-3813483.482, 3554283.228, 3662773.085\n299.9,-3813483.216, 3554282.815, 3662773.758\n"
  },
  {
    "path": "fifo.c",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <errno.h>\n#include <string.h>\n#include <pthread.h>\n#include <assert.h>\n#include \"fifo.h\"\n\nstatic pthread_mutex_t fifo_mutex = PTHREAD_MUTEX_INITIALIZER; // mutex protecting the queues\nstatic pthread_cond_t fifo_notempty_cond = PTHREAD_COND_INITIALIZER; // condition used to signal FIFO-not-empty\nstatic pthread_cond_t fifo_empty_cond = PTHREAD_COND_INITIALIZER; // condition used to signal FIFO-empty\nstatic pthread_cond_t fifo_free_cond = PTHREAD_COND_INITIALIZER; // condition used to signal freelist-not-empty\nstatic pthread_cond_t fifo_full_cond = PTHREAD_COND_INITIALIZER; // condition used to signal FIFO-full\nstatic struct iq_buf *fifo_head; // head of queued buffers awaiting demodulation\nstatic struct iq_buf *fifo_tail; // tail of queued buffers awaiting demodulation\nstatic struct iq_buf *fifo_freelist; // freelist of preallocated buffers\nstatic bool fifo_halted; // true if queue has been halted\n\n// Create the queue structures. Not threadsafe.\n\nbool fifo_create(unsigned buffer_count, unsigned buffer_size, unsigned sample_size) {\n    for (unsigned i = 0; i < buffer_count; ++i) {\n        struct iq_buf *newbuf;\n        if (!(newbuf = calloc(1, sizeof (*newbuf)))) {\n            goto nomem;\n        }\n\n        if (sample_size == sizeof (signed short)) {\n            if (!(newbuf->data16 = calloc(buffer_size, sizeof (newbuf->data16[0])))) {\n                free(newbuf);\n                goto nomem;\n            }\n            newbuf->data8 = NULL;\n        } else {\n            if (!(newbuf->data8 = calloc(buffer_size, sizeof (newbuf->data8[0])))) {\n                free(newbuf);\n                goto nomem;\n            }\n            newbuf->data16 = NULL;\n        }\n\n        newbuf->totalLength = buffer_size;\n        newbuf->validLength = 0;\n        newbuf->next = fifo_freelist;\n        fifo_freelist = newbuf;\n    }\n\n    return true;\n\nnomem:\n    fifo_destroy();\n    return false;\n}\n\nstatic void free_buffer_list(struct iq_buf *head) {\n    while (head) {\n        struct iq_buf *next = head->next;\n        free(head->data8);\n        free(head->data16);\n        free(head);\n        head = next;\n    }\n}\n\nvoid fifo_destroy() {\n    free_buffer_list(fifo_head);\n    free_buffer_list(fifo_freelist);\n    fifo_freelist = NULL;\n    fifo_head = fifo_tail = NULL;\n    pthread_cond_destroy(&fifo_notempty_cond);\n    pthread_cond_destroy(&fifo_full_cond);\n    pthread_cond_destroy(&fifo_free_cond);\n    pthread_cond_destroy(&fifo_empty_cond);\n    pthread_mutex_destroy(&fifo_mutex);\n}\n\nvoid fifo_wait_next() {\n    pthread_mutex_lock(&fifo_mutex);\n    while (fifo_head && !fifo_halted) {\n        pthread_cond_wait(&fifo_empty_cond, &fifo_mutex);\n    }\n    pthread_mutex_unlock(&fifo_mutex);\n}\n\nvoid fifo_wait_full() {\n    pthread_mutex_lock(&fifo_mutex);\n    if (!fifo_halted) {\n        pthread_cond_wait(&fifo_full_cond, &fifo_mutex);\n    }\n    pthread_mutex_unlock(&fifo_mutex);\n}\n\nvoid fifo_halt() {\n    pthread_mutex_lock(&fifo_mutex);\n\n    // Drain all enqueued buffers to the freelist\n    while (fifo_head) {\n        struct iq_buf *freebuf = fifo_head;\n        fifo_head = freebuf->next;\n\n        freebuf->next = fifo_freelist;\n        fifo_freelist = freebuf;\n    }\n\n    fifo_tail = NULL;\n    fifo_halted = true;\n\n    // wake all waiters\n    pthread_cond_broadcast(&fifo_notempty_cond);\n    pthread_cond_broadcast(&fifo_empty_cond);\n    pthread_cond_broadcast(&fifo_free_cond);\n    pthread_cond_broadcast(&fifo_full_cond);\n    pthread_mutex_unlock(&fifo_mutex);\n}\n\nstruct iq_buf *fifo_acquire(void) {\n    pthread_mutex_lock(&fifo_mutex);\n\n    struct iq_buf *result = NULL;\n    if (!fifo_halted && !fifo_freelist) {\n        pthread_cond_signal(&fifo_full_cond);\n        // No free buffers, wait for one\n        pthread_cond_wait(&fifo_free_cond, &fifo_mutex);\n    }\n\n    if (!fifo_halted) {\n        result = fifo_freelist;\n        fifo_freelist = result->next;\n\n        result->validLength = 0;\n        result->next = NULL;\n    }\n\n    pthread_mutex_unlock(&fifo_mutex);\n    return result;\n}\n\nvoid fifo_enqueue(struct iq_buf *buf) {\n    assert(buf->validLength <= buf->totalLength);\n\n    pthread_mutex_lock(&fifo_mutex);\n\n    if (fifo_halted) {\n        // Shutting down, just return the buffer to the freelist.\n        buf->next = fifo_freelist;\n        fifo_freelist = buf;\n        goto done;\n    }\n    // enqueue and tell the main thread\n    buf->next = NULL;\n    if (!fifo_head) {\n        fifo_head = fifo_tail = buf;\n        pthread_cond_signal(&fifo_notempty_cond);\n    } else {\n        fifo_tail->next = buf;\n    }\n\ndone:\n    pthread_mutex_unlock(&fifo_mutex);\n}\n\nstruct iq_buf *fifo_dequeue(void) {\n    pthread_mutex_lock(&fifo_mutex);\n\n    struct iq_buf *result = NULL;\n    if (!fifo_head && !fifo_halted) {\n        // No data pending, wait for some\n        pthread_cond_wait(&fifo_notempty_cond, &fifo_mutex);\n    }\n\n    if (!fifo_halted) {\n        result = fifo_head;\n        fifo_head = result->next;\n        result->next = NULL;\n        if (!fifo_head) {\n            fifo_tail = NULL;\n            pthread_cond_broadcast(&fifo_empty_cond);\n        }\n    }\n\n    pthread_mutex_unlock(&fifo_mutex);\n    return result;\n}\n\nvoid fifo_release(struct iq_buf *buf) {\n    pthread_mutex_lock(&fifo_mutex);\n    if (!fifo_freelist) {\n        pthread_cond_signal(&fifo_free_cond);\n    }\n    buf->next = fifo_freelist;\n    fifo_freelist = buf;\n    pthread_mutex_unlock(&fifo_mutex);\n}\n\n"
  },
  {
    "path": "fifo.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#ifndef FIFO_H\n#define FIFO_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\nstruct iq_buf {\n    signed char *data8; // 8 bit IQ data\n    signed short *data16; // 16 bit IQ data\n    unsigned int totalLength; // Maximum number of samples (allocated size of \"data\")\n    unsigned int validLength; // Number of valid samples in \"data\"\n    struct iq_buf *next; // linked list forward link\n};\n\n// Create the queue structures. Not threadsafe. Returns true on success.\n//\n//   buffer_count - the number of buffers to preallocate\n//   buffer_size  - the size of each IQ buffer, in samples\nbool fifo_create(unsigned buffer_count, unsigned buffer_size, unsigned sample_size);\n\n// Destroy the fifo structures allocated in fifo_create. Not threadsafe; ensure all FIFO users\n// are done before calling.\nvoid fifo_destroy();\n\n// Block until the FIFO is empty.\nvoid fifo_wait_next();\n\n// Block until the FIFO is full.\nvoid fifo_wait_full();\n\n// Mark the FIFO as halted. Move any buffers in FIFO to the freelist immediately.\nvoid fifo_halt();\n\n// Get an unused buffer from the freelist and return it.\n// Block waiting for a free buffer.\n// free buffers available within the timeout, or if the FIFO is halted.\nstruct iq_buf *fifo_acquire(void);\n\n// Put a filled buffer (previously obtained from fifo_acquire) onto the head of the FIFO.\n// The caller should have filled:\n//   buf->validLength\n//   buf->data[0 .. buf->validLength-1]\nvoid fifo_enqueue(struct iq_buf *buf);\n\n// Get a buffer from the tail of the FIFO.\n// If the FIFO is halted (or becomes halted), return NULL immediately.\n// return NULL if no data arrives\nstruct iq_buf *fifo_dequeue(void);\n\n// Release a buffer previously returned by fifo_acquire() back to the freelist.\nvoid fifo_release(struct iq_buf *buf);\n\n#endif"
  },
  {
    "path": "gps-sim.c",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <signal.h>\n#include <sched.h>\n#include <fcntl.h> \n#include <unistd.h>\n#include <sys/stat.h> \n#include <sys/types.h> \n#include <sys/time.h>\n#include \"help.h\"\n#include \"gui.h\"\n#include \"sdr.h\"\n#include \"gps-sim.h\"\n\nsimulator_t simulator;\n\nstatic error_t parse_opt(int key, char *arg, struct argp_state *state);\nconst char *argp_program_version = \"v1.0\";\nconst char args_doc[] = \"\";\nconst char doc[] = \"gps-sim generates a GPS L1 baseband signal IQ data stream, which is then transmitted by a software-defined radio (SDR) platform.\";\nstatic struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};\n\nstatic error_t parse_opt(int key, char *arg, struct argp_state *state) {\n    double d = 0.0;\n\n    switch (key) {\n        case 'e':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            simulator.nav_file_name = strdup(arg);\n            break;\n        case 'r':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            simulator.sdr_name = strdup(arg);\n            break;\n        case 'U':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            simulator.pluto_uri = strdup(arg);\n            break;\n        case 'N':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            simulator.pluto_hostname = strdup(arg);\n            break;\n        case 'm':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            simulator.motion_file_name = strdup(arg);\n            simulator.interactive_mode = false;\n            break;\n        case 701: // --station\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            simulator.station_id = strndup(arg, 9);\n            break;\n        case 'f':\n            simulator.use_ftp = true;\n            break;\n        case 'l':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            sscanf(arg, \"%lf,%lf,%lf\", &simulator.location.lat, &simulator.location.lon, &simulator.location.height);\n            break;\n        case 's':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            if (strncmp(arg, \"now\", 3) == 0) {\n                simulator.time_overwrite = true;\n                time_t timer;\n                struct tm *gmt;\n\n                time(&timer);\n                gmt = gmtime(&timer);\n\n                simulator.start.y = gmt->tm_year + 1900;\n                simulator.start.m = gmt->tm_mon + 1;\n                simulator.start.d = gmt->tm_mday;\n                simulator.start.hh = gmt->tm_hour;\n                simulator.start.mm = gmt->tm_min;\n                simulator.start.sec = (double) gmt->tm_sec;\n            } else {\n                sscanf(arg, \"%d/%d/%d,%d:%d:%lf\", &simulator.start.y, &simulator.start.m, &simulator.start.d, &simulator.start.hh, &simulator.start.mm, &simulator.start.sec);\n            }\n            if (simulator.start.y <= 1980 ||\n                    simulator.start.m < 1 || simulator.start.m > 12 ||\n                    simulator.start.d < 1 || simulator.start.d > 31 ||\n                    simulator.start.hh < 0 || simulator.start.hh > 23 ||\n                    simulator.start.mm < 0 || simulator.start.mm > 59 ||\n                    simulator.start.sec < 0.0 || simulator.start.sec >= 60.0) {\n                fprintf(stderr, \"ERROR: Invalid date and time.\\n\");\n                return ARGP_ERR_UNKNOWN;\n            }\n            break;\n        case 'I':\n            simulator.ionosphere_enable = false;\n            break;\n        case 'v':\n            simulator.show_verbose = true;\n            break;\n        case 'a':\n            simulator.enable_tx_amp = true;\n            break;\n        case 'g':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            simulator.tx_gain = (int) strtoul(arg, NULL, 10);\n            break;\n        case 'd':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            d = atof(arg);\n            if (d < 0.0 || d > ((double) USER_MOTION_SIZE) / 10.0) {\n                gui_status_wprintw(RED, \"Error: Invalid duration.\\n\");\n                return -1;\n            }\n            simulator.duration = (int) (d * 10.0 + 0.5);\n            break;\n        case 't':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            simulator.target.valid = true;\n            sscanf(arg, \"%lf,%lf,%lf\", &simulator.target.distance, &simulator.target.bearing, &simulator.target.height);\n            simulator.target.bearing *= 1000;\n            break;\n        case 'i':\n            simulator.interactive_mode = true;\n            break;\n        case '3':\n            simulator.use_rinex3 = true;\n            break;\n        case 'p':\n            if (arg == NULL) {\n                return ARGP_ERR_UNKNOWN;\n            }\n            simulator.ppb = atoi(arg);\n            break;\n        case 700: // --iq16\n            simulator.sample_size = SC16;\n            break;\n        case 702: // --disable-almanac\n            simulator.almanac_enable = false;\n            break;\n        case ARGP_KEY_END:\n            if (state->arg_num > 0)\n                /* We use only options but no arguments */\n                argp_usage(state);\n            break;\n        default:\n            return ARGP_ERR_UNKNOWN;\n    }\n    return 0;\n}\n\nstatic void simulator_init(void) {\n    simulator.main_exit = false;\n    simulator.show_verbose = false;\n    simulator.ionosphere_enable = true;\n    simulator.gps_thread_running = false;\n    simulator.interactive_mode = false;\n    simulator.use_ftp = false;\n    simulator.enable_tx_amp = false;\n    simulator.use_rinex3 = false;\n    simulator.time_overwrite = false;\n    simulator.almanac_enable = true;\n    simulator.duration = USER_MOTION_SIZE;\n    simulator.tx_gain = 0;\n    simulator.ppb = 0;\n    simulator.location.lat = 0;\n    simulator.location.lon = 0;\n    simulator.location.height = 0;\n    simulator.target.bearing = 0;\n    simulator.target.distance = 0;\n    simulator.target.lat = 0;\n    simulator.target.lon = 0;\n    simulator.target.height = 0;\n    simulator.target.valid = false;\n    simulator.nav_file_name = NULL;\n    simulator.sdr_name = NULL;\n    simulator.pluto_hostname = NULL;\n    simulator.motion_file_name = NULL;\n    simulator.pluto_uri = NULL;\n    simulator.station_id = NULL;\n    simulator.sdr_type = SDR_NONE;\n    simulator.sample_size = SC08;\n    pthread_cond_init(&simulator.gps_init_done, NULL);\n    pthread_mutex_init(&simulator.gps_lock, NULL);\n}\n\nstatic void signal_handler(int sig) {\n    signal(sig, SIG_DFL); // Reset signal handler\n    simulator.main_exit = true;\n    gui_status_wprintw(RED, \"Caught signal %s, shutting down\\n\", strsignal(sig));\n}\n\nstatic void cleanup_and_exit(int code) {\n    simulator.gps_thread_exit = true;\n    pthread_join(simulator.gps_thread, NULL); /* Wait on GPS read thread exit */\n\n    pthread_cond_destroy(&simulator.gps_init_done);\n    pthread_mutex_destroy(&simulator.gps_lock);\n\n    /* Free when pointing to string in heap (strdup allocated when given as run option) */\n    free(simulator.nav_file_name);\n    free(simulator.sdr_name);\n    free(simulator.pluto_hostname);\n    free(simulator.pluto_uri);\n    free(simulator.motion_file_name);\n    free(simulator.station_id);\n    sdr_close();\n    gui_destroy();\n    fflush(stdout);\n    exit(code);\n}\n\n/* Set trhead name if supported. */\nvoid set_thread_name(const char *name) {\n#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 12)\n    pthread_setname_np(pthread_self(), name);\n#else\n    NOTUSED(name);\n#endif\n}\n\n// Set affinity of calling thread to specific core on a multi-core CPU\n\nint thread_to_core(int core_id) {\n    int num_cores = sysconf(_SC_NPROCESSORS_ONLN);\n    if (core_id < 0 || core_id >= num_cores)\n        return EINVAL;\n\n    cpu_set_t cpuset;\n    CPU_ZERO(&cpuset);\n    CPU_SET(core_id, &cpuset);\n\n    pthread_t current_thread = pthread_self();\n    return pthread_setaffinity_np(current_thread, sizeof (cpu_set_t), &cpuset);\n}\n\n/*\n * \n */\nint main(int argc, char** argv) {\n    int ch = 0;\n    bool is_info_shown = false;\n    bool is_help_shown = false;\n\n    // signal handlers:\n    signal(SIGINT, signal_handler);\n    signal(SIGTERM, signal_handler);\n    signal(SIGABRT, signal_handler);\n\n    // Initialize all simulator variables\n    simulator_init();\n    /* On a multi-core CPU we run the main thread and reader thread on different cores.\n     * Try sticking the main thread to core 1\n     */\n    thread_to_core(1);\n    set_thread_name(\"simulator-thread\");\n\n    // Parse the command line options\n    if (argp_parse(&argp, argc, argv, 0, 0, 0)) {\n        return (EXIT_FAILURE);\n    }\n\n    if (simulator.nav_file_name == NULL && simulator.use_ftp == false) {\n        fprintf(stderr, \"Error: GPS ephemeris file is not specified\\n\");\n        return (EXIT_FAILURE);\n    }\n    gui_init();\n    // No access to GUI until this point\n\n    if (simulator.interactive_mode && simulator.motion_file_name != NULL) {\n        simulator.interactive_mode = false;\n        simulator.target.valid = false;\n        gui_status_wprintw(YELLOW, \"User motion file supplied. Interactive mode disabled!\\n\");\n    }\n\n    // Wait maximum 30 seconds for GPS thread to become ready\n    struct timespec timeout;\n    struct timeval now;\n    gettimeofday(&now, NULL);\n    timeout.tv_sec = now.tv_sec + 30;\n    timeout.tv_nsec = 0;\n\n    // Init prior GPS thread, creates FIFO.\n    if (sdr_init(&simulator) == 0) {\n        // Start GPS baseband signal generation\n        gui_top_panel(LS_FIX);\n        pthread_create(&simulator.gps_thread, NULL, gps_thread_ep, &simulator);\n\n        pthread_mutex_lock(&(simulator.gps_lock));\n        int ret = pthread_cond_timedwait(&(simulator.gps_init_done), &(simulator.gps_lock), &timeout);\n        pthread_mutex_unlock(&(simulator.gps_lock));\n\n        if (ret == ETIMEDOUT) {\n            gui_status_wprintw(RED, \"Time out waiting for GPS thread. Running?\\n\");\n        }\n\n        if (!simulator.gps_thread_exit) {\n            if (sdr_run() != 0) {\n                gui_status_wprintw(RED, \"Starting SDR streaming failed.\\n\");\n                simulator.gps_thread_exit = true;\n            }\n        }\n    }\n    // Run this until we get a termination signal.\n    while (!simulator.main_exit) {\n        ch = gui_getch();\n        if (ch != -1) {\n            switch (ch) {\n                case 'x':\n                case 'X':\n                    simulator.main_exit = true;\n                    break;\n                case 'i':\n                case 'I':\n                    gui_show_panel(INFO, ON);\n                    is_info_shown = true;\n                    break;\n                case '?':\n                case 'h':\n                case 'H':\n                    gui_show_panel(HELP, ON);\n                    is_help_shown = true;\n                    break;\n                case 9: // TAB\n                    gui_toggle_current_panel();\n                    break;\n                case 265: // F1\n                    gui_top_panel(TRACK);\n                    break;\n                case 266: // F2\n                    gui_top_panel(LS_FIX);\n                    break;\n                case 267: // F3\n                    gui_top_panel(KF_FIX);\n                    break;\n                case LEFT_KEY:\n                    simulator.target.bearing -= 127.0;\n                    if (simulator.target.bearing < 0) simulator.target.bearing = 360000.0;\n                    if (simulator.target.bearing > 360000) simulator.target.bearing = 0;\n                    gui_show_heading((float) (simulator.target.bearing / 1000));\n                    break;\n                case RIGHT_KEY:\n                    simulator.target.bearing += 127.0;\n                    if (simulator.target.bearing < 0) simulator.target.bearing = 360000.0;\n                    if (simulator.target.bearing > 360000) simulator.target.bearing = 0;\n                    gui_show_heading((float) (simulator.target.bearing / 1000));\n                    break;\n                case UP_KEY:\n                    simulator.target.vertical_speed += 1;\n                    gui_show_vertical_speed((float) simulator.target.vertical_speed);\n                    break;\n                case DOWN_KEY:\n                    simulator.target.vertical_speed -= 1;\n                    gui_show_vertical_speed((float) simulator.target.vertical_speed);\n                    break;\n                case UPSPEED_KEY:\n                    simulator.target.speed += 1.0;\n                    simulator.target.velocity = simulator.target.speed / 100.0;\n                    gui_show_speed((float) (simulator.target.velocity * 3.6));\n                    break;\n                case DOWNSPEED_KEY:\n                    simulator.target.speed -= 1.0;\n                    if (simulator.target.speed < 0) simulator.target.speed = 0;\n                    simulator.target.velocity = simulator.target.speed / 100.0;\n                    gui_show_speed((float) (simulator.target.velocity * 3.6));\n                    break;\n                case GAIN_INC_KEY:\n                    simulator.tx_gain = sdr_set_gain(simulator.tx_gain + 1);\n                    gui_status_wprintw(GREEN, \"Gain: %ddB.\\r\", simulator.tx_gain);\n                    break;\n                case GAIN_DEC_KEY:\n                    simulator.tx_gain = sdr_set_gain(simulator.tx_gain - 1);\n                    gui_status_wprintw(GREEN, \"Gain: %ddB.\\r\", simulator.tx_gain);\n                    break;\n                default:\n                    if (is_info_shown) {\n                        gui_show_panel(INFO, OFF);\n                        is_info_shown = false;\n                    }\n                    if (is_help_shown) {\n                        gui_show_panel(HELP, OFF);\n                        is_help_shown = false;\n                    }\n                    break;\n            }\n        }\n    }\n\n    cleanup_and_exit(EXIT_SUCCESS);\n    return (EXIT_SUCCESS);\n}\n\n"
  },
  {
    "path": "gps-sim.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#ifndef GPS_SIM_H\n#define GPS_SIM_H\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <stdbool.h>\n#include <pthread.h>\n#include <stdatomic.h>\n#include \"gps.h\"\n\n#define NOTUSED(V) ((void) V)\n\n// Sampling data format\n#define SC08 sizeof(signed char)\n#define SC16 sizeof(signed short)\n\n/* SDR device types */\ntypedef enum {\n    SDR_NONE = 0, SDR_IQFILE, SDR_HACKRF, SDR_PLUTOSDR\n} sdr_type_t;\n\n/* Target information. */\ntypedef struct {\n    double bearing;\n    double distance;\n    double lat;\n    double lon;\n    double height;\n    double velocity;\n    double speed;\n    double vertical_speed;\n    bool valid;\n} target_t;\n\n/* Simulator location. */\ntypedef struct {\n    double lat; // Latitude\n    double lon; // Longitude\n    double height; // Height/Elevation\n} location_t;\n\n/* All the GPS simulators variables. */\ntypedef struct {\n    atomic_bool main_exit;\n    atomic_bool gps_thread_exit;\n    atomic_bool gps_thread_running;\n    bool show_verbose;\n    bool ionosphere_enable;\n    bool interactive_mode;\n    bool use_ftp;\n    bool enable_tx_amp;\n    bool use_rinex3;\n    bool time_overwrite;\n    bool almanac_enable;\n    int duration;\n    int tx_gain;\n    int ppb;\n    int sample_size;\n    sdr_type_t sdr_type;\n    char *nav_file_name;\n    char *motion_file_name;\n    char *sdr_name;\n    char *pluto_uri;\n    char *pluto_hostname;\n    char *station_id;\n    pthread_mutex_t gps_lock;\n    pthread_t gps_thread;\n    pthread_cond_t gps_init_done; // Condition signals GPS thread is running\n    location_t location; // Simulator geo location\n    target_t target; // Target information\n    datetime_t start; // Simulation start time\n} simulator_t;\n\nvoid set_thread_name(const char *name);\nint thread_to_core(int core_id);\n\n#endif /* GPS_SIM_H */\n\n"
  },
  {
    "path": "gps.c",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n#include <time.h>\n#include <pthread.h>\n#include <errno.h>\n#include <curl/curl.h>\n#include <zlib.h>\n#include \"sdr.h\"\n#include \"gui.h\"\n#include \"fifo.h\"\n#include \"almanac.h\"\n#include \"gps-sim.h\"\n\n/**\n * Note:\n * Not all stations provide RINEX data with ionosphere data.\n */\n\n/**\n * Stations providing Rinex v3 format.\n * 4-characters station ID\n * 9-characters station ID\n * Station name\n * Including Ionosphere data in Rinex file\n */\nconst stations_t stations_v3[] = {\n    {\"func\", \"FUNC00PRT\", \"Funchal\"},\n    {\"flrs\", \"FLRS00PRT\", \"Santa Cruz das Flore\"},\n    {\"pdel\", \"PDEL00PRT\", \"PONTA DELGADA\"},\n    {NULL, NULL, NULL} // Always last entry\n};\n\n/**\n * Stations providing Rinex v2 format.\n * 4-characters station ID\n * 9-characters station ID\n * Station name\n */\nconst stations_t stations_v2[] = {\n    {\"abmf\", \"ABMF00GLP\", \"Aeroport du Raizet\"},\n    {\"aggo\", \"AGGO00ARG\", \"AGGO\"},\n    {\"ajac\", \"AJAC00FRA\", \"Ajaccio\"},\n    {\"ankr\", \"ANKR00TUR\", \"Ankara\"},\n    {\"areg\", \"AREG00PER\", \"Arequipa\"},\n    {\"ascg\", \"ASCG00SHN\", \"Ascension\"},\n    {\"bogi\", \"BOGI00POL\", \"Borowa Gora\"},\n    {\"bor1\", \"BOR100POL\", \"Borowiec\"},\n    {\"brst\", \"BRST00FRA\", \"Brest\"},\n    {\"chpg\", \"CHPG00BRA\", \"Cachoeira Paulista\"},\n    {\"cibg\", \"CIBG00IDN\", \"Cibinong\"},\n    {\"cpvg\", \"CPVG00CPV\", \"CAP-VERT\"},\n    {\"djig\", \"DJIG00DJI\", \"Djibouti\"},\n    {\"dlf1\", \"DLF100NLD\", \"Delft\"},\n    {\"ffmj\", \"FFMJ00DEU\", \"Frankfurt/Main\"},\n    {\"ftna\", \"FTNA00WLF\", \"Futuna\"},\n    {\"gamb\", \"GAMB00PYF\", \"Rikitea\"},\n    {\"gamg\", \"GAMG00KOR\", \"Geochang\"},\n    {\"glps\", \"GLPS00ECU\", \"Galapagos Permanent Station\"},\n    {\"glsv\", \"GLSV00UKR\", \"Kiev/Golosiiv\"},\n    {\"gmsd\", \"GMSD00JPN\", \"GUTS Masda\"},\n    {\"gop6\", \"GOP600CZE\", \"Pecny, Ondrejov\"},\n    {\"gop7\", \"GOP700CZE\", \"Pecny, Ondrejov\"},\n    {\"gope\", \"GOPE00CZE\", \"Pecny, Ondrejov\"},\n    {\"grac\", \"GRAC00FRA\", \"Grasse\"},\n    {\"gras\", \"GRAS00FRA\", \"Observatoire de Calern - OCA\"},\n    {\"holb\", \"HOLB00CAN\", \"Holberg\"},\n    {\"hueg\", \"HUEG00DEU\", \"Huegelheim\"},\n    {\"ieng\", \"IENG00ITA\", \"Torino\"},\n    {\"ista\", \"ISTA00TUR\", \"Istanbul\"},\n    {\"izmi\", \"IZMI00TUR\", \"Izmir\"},\n    {\"jfng\", \"JFNG00CHN\", \"Juifeng\"},\n    {\"joz2\", \"JOZ200POL\", \"Jozefoslaw\"},\n    {\"joze\", \"JOZE00POL\", \"Jozefoslaw\"},\n    {\"kerg\", \"KERG00ATF\", \"Kerguelen Islands\"},\n    {\"kitg\", \"KITG00UZB\", \"Kitab\"},\n    {\"koug\", \"KOUG00GUF\", \"Kourou\"},\n    {\"krgg\", \"KRGG00ATF\", \"Kerguelen Islands\"},\n    {\"krs1\", \"KRS100TUR\", \"Kars\"},\n    {\"lama\", \"LAMA00POL\", \"Lamkowo\"},\n    {\"leij\", \"LEIJ00DEU\", \"Leipzig\"},\n    {\"lmmf\", \"LMMF00MTQ\", \"Aeroport Aime CESAIRE-LE LAMENTIN\"},\n    {\"lroc\", \"LROC00FRA\", \"La Rochelle\"},\n    {\"mad2\", \"MAD200ESP\", \"Madrid Deep Space Tracking Station\"},\n    {\"madr\", \"MADR00ESP\", \"Madrid Deep Space Tracking Station\"},\n    {\"mayg\", \"MAYG00MYT\", \"Dzaoudzi\"},\n    {\"mers\", \"MERS00TUR\", \"Mersin\"},\n    {\"mikl\", \"MIKL00UKR\", \"Mykolaiv\"},\n    {\"morp\", \"MORP00GBR\", \"Morpeth\"},\n    {\"nklg\", \"NKLG00GAB\", \"N'KOLTANG\"},\n    {\"nyal\", \"NYAL00NOR\", \"Ny-Alesund\"},\n    {\"nya1\", \"NYA100NOR\", \"Ny-Alesund\"},\n    {\"ohi2\", \"OHI200ATA\", \"O'Higgins\"},\n    {\"orid\", \"ORID00MKD\", \"Ohrid\"},\n    {\"owmg\", \"OWMG00NZL\", \"Chatham Island\"},\n    {\"polv\", \"POLV00UKR\", \"Poltava\"},\n    {\"ptbb\", \"PTBB00DEU\", \"Braunschweig\"},\n    {\"ptgg\", \"PTGG00PHL\", \"Manilla\"},\n    {\"rabt\", \"RABT00MAR\", \"Rabat, EMI\"},\n    {\"reun\", \"REUN00REU\", \"La Reunion - Observatoire Volcanologique\"},\n    {\"rgdg\", \"RGDG00ARG\", \"Rio Grande\"},\n    {\"riga\", \"RIGA00LVA\", \"RIGA permanent GPS\"},\n    {\"seyg\", \"SEYG00SYC\", \"Mahe\"},\n    {\"sofi\", \"SOFI00BGR\", \"Sofia\"},\n    {\"stj3\", \"STJ300CAN\", \"STJ3 CACS-GSD\"},\n    {\"sulp\", \"SULP00UKR\", \"Lviv Polytechnic\"},\n    {\"svtl\", \"SVTL00RUS\", \"Svetloe\"},\n    {\"tana\", \"TANA00ETH\", \"ILA, Bahir Dar University\"},\n    {\"thtg\", \"THTG00PYF\", \"Papeete Tahiti\"},\n    {\"thti\", \"THTI00PYF\", \"Tahiti\"},\n    {\"tit2\", \"TIT200DEU\", \"Titz / Jackerath\"},\n    {\"tlse\", \"TLSE00FRA\", \"Toulouse\"},\n    {\"tro1\", \"TRO100NOR\", \"Tromsoe\"},\n    {\"warn\", \"WARN00DEU\", \"Warnemuende\"},\n    {\"whit\", \"WHIT00CAN\", \"WHIT CACS-GSD\"},\n    {\"wroc\", \"WROC00POL\", \"Wroclaw\"},\n    {\"wtza\", \"WTZA00DEU\", \"Wettzell\"},\n    {\"yel2\", \"YEL200CAN\", \"Yellow Knife\"},\n    {\"zeck\", \"ZECK00RUS\", \"Zelenchukskaya\"},\n    {\"zim2\", \"ZIM200CHE\", \"Zimmerwald\"},\n    {\"zimm\", \"ZIMM00CHE\", \"Zimmerwald L+T 88\"},\n    {NULL, NULL, NULL} // Always last entry\n};\n\nstatic char rinex_date[21];\n\nstruct ftp_file {\n    const char *filename;\n    FILE *stream;\n};\n\nconst int sinTable512[] = {\n    2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47,\n    50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 91, 94,\n    97, 100, 103, 105, 108, 111, 114, 116, 119, 122, 125, 127, 130, 132, 135, 138,\n    140, 143, 145, 148, 150, 153, 155, 157, 160, 162, 164, 167, 169, 171, 173, 176,\n    178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 205, 207,\n    209, 210, 212, 214, 215, 217, 218, 220, 221, 223, 224, 225, 227, 228, 229, 230,\n    232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 241, 242, 243, 244, 244, 245,\n    245, 246, 247, 247, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 250,\n    250, 250, 250, 250, 250, 249, 249, 249, 249, 248, 248, 248, 247, 247, 246, 245,\n    245, 244, 244, 243, 242, 241, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232,\n    230, 229, 228, 227, 225, 224, 223, 221, 220, 218, 217, 215, 214, 212, 210, 209,\n    207, 205, 204, 202, 200, 198, 196, 194, 192, 190, 188, 186, 184, 182, 180, 178,\n    176, 173, 171, 169, 167, 164, 162, 160, 157, 155, 153, 150, 148, 145, 143, 140,\n    138, 135, 132, 130, 127, 125, 122, 119, 116, 114, 111, 108, 105, 103, 100, 97,\n    94, 91, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, 59, 56, 53, 50,\n    47, 44, 41, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2,\n    -2, -5, -8, -11, -14, -17, -20, -23, -26, -29, -32, -35, -38, -41, -44, -47,\n    -50, -53, -56, -59, -62, -65, -68, -71, -74, -77, -80, -83, -86, -89, -91, -94,\n    -97, -100, -103, -105, -108, -111, -114, -116, -119, -122, -125, -127, -130, -132, -135, -138,\n    -140, -143, -145, -148, -150, -153, -155, -157, -160, -162, -164, -167, -169, -171, -173, -176,\n    -178, -180, -182, -184, -186, -188, -190, -192, -194, -196, -198, -200, -202, -204, -205, -207,\n    -209, -210, -212, -214, -215, -217, -218, -220, -221, -223, -224, -225, -227, -228, -229, -230,\n    -232, -233, -234, -235, -236, -237, -238, -239, -240, -241, -241, -242, -243, -244, -244, -245,\n    -245, -246, -247, -247, -248, -248, -248, -249, -249, -249, -249, -250, -250, -250, -250, -250,\n    -250, -250, -250, -250, -250, -249, -249, -249, -249, -248, -248, -248, -247, -247, -246, -245,\n    -245, -244, -244, -243, -242, -241, -241, -240, -239, -238, -237, -236, -235, -234, -233, -232,\n    -230, -229, -228, -227, -225, -224, -223, -221, -220, -218, -217, -215, -214, -212, -210, -209,\n    -207, -205, -204, -202, -200, -198, -196, -194, -192, -190, -188, -186, -184, -182, -180, -178,\n    -176, -173, -171, -169, -167, -164, -162, -160, -157, -155, -153, -150, -148, -145, -143, -140,\n    -138, -135, -132, -130, -127, -125, -122, -119, -116, -114, -111, -108, -105, -103, -100, -97,\n    -94, -91, -89, -86, -83, -80, -77, -74, -71, -68, -65, -62, -59, -56, -53, -50,\n    -47, -44, -41, -38, -35, -32, -29, -26, -23, -20, -17, -14, -11, -8, -5, -2\n};\n\nconst int cosTable512[] = {\n    250, 250, 250, 250, 250, 249, 249, 249, 249, 248, 248, 248, 247, 247, 246, 245,\n    245, 244, 244, 243, 242, 241, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232,\n    230, 229, 228, 227, 225, 224, 223, 221, 220, 218, 217, 215, 214, 212, 210, 209,\n    207, 205, 204, 202, 200, 198, 196, 194, 192, 190, 188, 186, 184, 182, 180, 178,\n    176, 173, 171, 169, 167, 164, 162, 160, 157, 155, 153, 150, 148, 145, 143, 140,\n    138, 135, 132, 130, 127, 125, 122, 119, 116, 114, 111, 108, 105, 103, 100, 97,\n    94, 91, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, 59, 56, 53, 50,\n    47, 44, 41, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2,\n    -2, -5, -8, -11, -14, -17, -20, -23, -26, -29, -32, -35, -38, -41, -44, -47,\n    -50, -53, -56, -59, -62, -65, -68, -71, -74, -77, -80, -83, -86, -89, -91, -94,\n    -97, -100, -103, -105, -108, -111, -114, -116, -119, -122, -125, -127, -130, -132, -135, -138,\n    -140, -143, -145, -148, -150, -153, -155, -157, -160, -162, -164, -167, -169, -171, -173, -176,\n    -178, -180, -182, -184, -186, -188, -190, -192, -194, -196, -198, -200, -202, -204, -205, -207,\n    -209, -210, -212, -214, -215, -217, -218, -220, -221, -223, -224, -225, -227, -228, -229, -230,\n    -232, -233, -234, -235, -236, -237, -238, -239, -240, -241, -241, -242, -243, -244, -244, -245,\n    -245, -246, -247, -247, -248, -248, -248, -249, -249, -249, -249, -250, -250, -250, -250, -250,\n    -250, -250, -250, -250, -250, -249, -249, -249, -249, -248, -248, -248, -247, -247, -246, -245,\n    -245, -244, -244, -243, -242, -241, -241, -240, -239, -238, -237, -236, -235, -234, -233, -232,\n    -230, -229, -228, -227, -225, -224, -223, -221, -220, -218, -217, -215, -214, -212, -210, -209,\n    -207, -205, -204, -202, -200, -198, -196, -194, -192, -190, -188, -186, -184, -182, -180, -178,\n    -176, -173, -171, -169, -167, -164, -162, -160, -157, -155, -153, -150, -148, -145, -143, -140,\n    -138, -135, -132, -130, -127, -125, -122, -119, -116, -114, -111, -108, -105, -103, -100, -97,\n    -94, -91, -89, -86, -83, -80, -77, -74, -71, -68, -65, -62, -59, -56, -53, -50,\n    -47, -44, -41, -38, -35, -32, -29, -26, -23, -20, -17, -14, -11, -8, -5, -2,\n    2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47,\n    50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 91, 94,\n    97, 100, 103, 105, 108, 111, 114, 116, 119, 122, 125, 127, 130, 132, 135, 138,\n    140, 143, 145, 148, 150, 153, 155, 157, 160, 162, 164, 167, 169, 171, 173, 176,\n    178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 205, 207,\n    209, 210, 212, 214, 215, 217, 218, 220, 221, 223, 224, 225, 227, 228, 229, 230,\n    232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 241, 242, 243, 244, 244, 245,\n    245, 246, 247, 247, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 250\n};\n\n// Receiver antenna attenuation in dB for boresight angle = 0:5:180 [deg]\nconst double ant_pat_db[37] = {\n    0.00, 0.00, 0.22, 0.44, 0.67, 1.11, 1.56, 2.00, 2.44, 2.89, 3.56, 4.22,\n    4.89, 5.56, 6.22, 6.89, 7.56, 8.22, 8.89, 9.78, 10.67, 11.56, 12.44, 13.33,\n    14.44, 15.56, 16.67, 17.78, 18.89, 20.00, 21.33, 22.67, 24.00, 25.56, 27.33, 29.33,\n    31.56\n};\n// Page number to SVID conversion for subframe 4&5\n// See IS-GPS-200L, p.110, table 20-V\nconst unsigned long sbf4_svId[25] = {\n    57UL, 0UL, 0UL, 0UL, 0UL, 57UL, 0UL, 0UL, 0UL, 0UL,\n    57UL, 62UL, 52UL, 53UL, 54UL, 57UL, 55UL, 56UL, 58UL,\n    59UL, 57UL, 60UL, 61UL, 62UL, 63UL\n};\n\nconst unsigned long sbf5_svId[25] = {\n    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL,\n    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL,\n    0UL, 0UL, 0UL, 0UL, 51UL\n};\n\nstatic int allocatedSat[MAX_SAT];\n\n/* Subtract two vectors of double\n * y Result of subtraction\n * x1 Minuend of subtracion\n * x2 Subtrahend of subtracion\n */\nstatic void subVect(double *y, const double *x1, const double *x2) {\n    y[0] = x1[0] - x2[0];\n    y[1] = x1[1] - x2[1];\n    y[2] = x1[2] - x2[2];\n\n    return;\n}\n\n/* Compute Norm of Vector\n * x Input vector\n * Length (Norm) of the input vector\n */\nstatic double normVect(const double *x) {\n    return (sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]));\n}\n\n/* Compute dot-product of two vectors\n * x1 First multiplicand\n * x2 Second multiplicand\n * Dot-product of both multiplicands\n */\nstatic double dotProd(const double *x1, const double *x2) {\n    return (x1[0] * x2[0] + x1[1] * x2[1] + x1[2] * x2[2]);\n}\n\n/* Generate the C/A code sequence for a given Satellite Vehicle PRN\n * prn PRN nuber of the Satellite Vehicle\n * ca Caller-allocated integer array of 1023 bytes\n */\nstatic void codegen(int *ca, int prn) {\n    int delay[] = {\n        5, 6, 7, 8, 17, 18, 139, 140, 141, 251,\n        252, 254, 255, 256, 257, 258, 469, 470, 471, 472,\n        473, 474, 509, 512, 513, 514, 515, 516, 859, 860,\n        861, 862\n    };\n\n    int g1[CA_SEQ_LEN], g2[CA_SEQ_LEN];\n    int r1[N_DWRD_SBF], r2[N_DWRD_SBF];\n    int c1, c2;\n    int i, j;\n\n    if (prn < 1 || prn > 32)\n        return;\n\n    for (i = 0; i < N_DWRD_SBF; i++)\n        r1[i] = r2[i] = -1;\n\n    for (i = 0; i < CA_SEQ_LEN; i++) {\n        g1[i] = r1[9];\n        g2[i] = r2[9];\n        c1 = r1[2] * r1[9];\n        c2 = r2[1] * r2[2] * r2[5] * r2[7] * r2[8] * r2[9];\n\n        for (j = 9; j > 0; j--) {\n            r1[j] = r1[j - 1];\n            r2[j] = r2[j - 1];\n        }\n        r1[0] = c1;\n        r2[0] = c2;\n    }\n\n    for (i = 0, j = CA_SEQ_LEN - delay[prn - 1]; i < CA_SEQ_LEN; i++, j++)\n        ca[i] = (1 - g1[i] * g2[j % CA_SEQ_LEN]) / 2;\n\n    return;\n}\n\n/* Convert a UTC date into a GPS date\n * t input date in UTC form\n * g output date in GPS form\n */\nstatic void date2gps(const datetime_t *t, gpstime_t *g) {\n    int doy[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};\n    int ye;\n    int de;\n    int lpdays;\n\n    ye = t->y - 1980;\n\n    // Compute the number of leap days since Jan 5/Jan 6, 1980.\n    lpdays = ye / 4 + 1;\n    if ((ye % 4) == 0 && t->m <= 2)\n        lpdays--;\n\n    // Compute the number of days elapsed since Jan 5/Jan 6, 1980.\n    de = ye * 365 + doy[t->m - 1] + t->d + lpdays - 6;\n\n    // Convert time to GPS weeks and seconds.\n    g->week = de / 7;\n    g->sec = (double) (de % 7) * SECONDS_IN_DAY + t->hh * SECONDS_IN_HOUR\n            + t->mm * SECONDS_IN_MINUTE + t->sec;\n\n    return;\n}\n\nstatic void gps2date(const gpstime_t *g, datetime_t *t) {\n    // Convert Julian day number to calendar date\n    int c = (int) (7 * g->week + floor(g->sec / 86400.0) + 2444245.0) + 1537;\n    int d = (int) ((c - 122.1) / 365.25);\n    int e = 365 * d + d / 4;\n    int f = (int) ((c - e) / 30.6001);\n\n    t->d = c - e - (int) (30.6001 * f);\n    t->m = f - 1 - 12 * (f / 14);\n    t->y = d - 4715 - ((7 + t->m) / 10);\n\n    t->hh = ((int) (g->sec / 3600.0)) % 24;\n    t->mm = ((int) (g->sec / 60.0)) % 60;\n    t->sec = g->sec - 60.0 * floor(g->sec / 60.0);\n\n    return;\n}\n\n/* Convert Earth-centered Earth-fixed (ECEF) into Lat/Long/Height\n * xyz Input Array of X, Y and Z ECEF coordinates\n * llh Output Array of Latitude, Longitude and Height\n */\nstatic void xyz2llh(const double *xyz, double *llh) {\n    double a, eps, e, e2;\n    double x, y, z;\n    double rho2, dz, zdz, nh, slat, n, dz_new;\n\n    a = WGS84_RADIUS;\n    e = WGS84_ECCENTRICITY;\n\n    eps = 1.0e-3;\n    e2 = e*e;\n\n    if (normVect(xyz) < eps) {\n        // Invalid ECEF vector\n        llh[0] = 0.0;\n        llh[1] = 0.0;\n        llh[2] = -a;\n\n        return;\n    }\n\n    x = xyz[0];\n    y = xyz[1];\n    z = xyz[2];\n\n    rho2 = x * x + y*y;\n    dz = e2*z;\n\n    while (1) {\n        zdz = z + dz;\n        nh = sqrt(rho2 + zdz * zdz);\n        slat = zdz / nh;\n        n = a / sqrt(1.0 - e2 * slat * slat);\n        dz_new = n * e2*slat;\n\n        if (fabs(dz - dz_new) < eps)\n            break;\n\n        dz = dz_new;\n    }\n\n    llh[0] = atan2(zdz, sqrt(rho2));\n    llh[1] = atan2(y, x);\n    llh[2] = nh - n;\n\n    return;\n}\n\n/* Convert Lat/Long/Height into Earth-centered Earth-fixed (ECEF)\n * llh Input Array of Latitude, Longitude and Height\n * xyz Output Array of X, Y and Z ECEF coordinates\n */\nstatic void llh2xyz(const double *llh, double *xyz) {\n    double n;\n    double a;\n    double e;\n    double e2;\n    double clat;\n    double slat;\n    double clon;\n    double slon;\n    double d, nph;\n    double tmp;\n\n    a = WGS84_RADIUS;\n    e = WGS84_ECCENTRICITY;\n    e2 = e*e;\n\n    clat = cos(llh[0]);\n    slat = sin(llh[0]);\n    clon = cos(llh[1]);\n    slon = sin(llh[1]);\n    d = e*slat;\n\n    n = a / sqrt(1.0 - d * d);\n    nph = n + llh[2];\n\n    tmp = nph*clat;\n    xyz[0] = tmp*clon;\n    xyz[1] = tmp*slon;\n    xyz[2] = ((1.0 - e2) * n + llh[2]) * slat;\n\n    return;\n}\n\n/* Compute the intermediate matrix for LLH to ECEF\n * llh Input position in Latitude-Longitude-Height format\n * t Three-by-Three output matrix\n */\nstatic void ltcmat(const double *llh, double t[3][3]) {\n    double slat, clat;\n    double slon, clon;\n\n    slat = sin(llh[0]);\n    clat = cos(llh[0]);\n    slon = sin(llh[1]);\n    clon = cos(llh[1]);\n\n    t[0][0] = -slat*clon;\n    t[0][1] = -slat*slon;\n    t[0][2] = clat;\n    t[1][0] = -slon;\n    t[1][1] = clon;\n    t[1][2] = 0.0;\n    t[2][0] = clat*clon;\n    t[2][1] = clat*slon;\n    t[2][2] = slat;\n\n    return;\n}\n\n/* Convert Earth-centered Earth-Fixed to ?\n * xyz Input position as vector in ECEF format\n * t Intermediate matrix computed by \\ref ltcmat\n * neu Output position as North-East-Up format\n */\nstatic void ecef2neu(const double *xyz, double t[3][3], double *neu) {\n    neu[0] = t[0][0] * xyz[0] + t[0][1] * xyz[1] + t[0][2] * xyz[2];\n    neu[1] = t[1][0] * xyz[0] + t[1][1] * xyz[1] + t[1][2] * xyz[2];\n    neu[2] = t[2][0] * xyz[0] + t[2][1] * xyz[1] + t[2][2] * xyz[2];\n\n    return;\n}\n\n/* Convert North-Eeast-Up to Azimuth + Elevation\n * neu Input position in North-East-Up format\n * azel Output array of azimuth + elevation as double\n */\nstatic void neu2azel(double *azel, const double *neu) {\n    double ne;\n\n    azel[0] = atan2(neu[1], neu[0]);\n    if (azel[0] < 0.0)\n        azel[0] += (2.0 * PI);\n\n    ne = sqrt(neu[0] * neu[0] + neu[1] * neu[1]);\n    azel[1] = atan2(neu[2], ne);\n\n    return;\n}\n\n/* Compute Satellite position, velocity and clock at given time\n * eph Ephemeris data of the satellite\n * g GPS time at which position is to be computed\n * pos Computed position (vector)\n * vel Computed velociy (vector)\n * clk Computed clock\n */\nstatic void satpos(ephem_t eph, gpstime_t g, double *pos, double *vel, double *clk) {\n    // Computing Satellite Velocity using the Broadcast Ephemeris\n    // http://www.ngs.noaa.gov/gps-toolbox/bc_velo.htm\n\n    double tk;\n    double mk;\n    double ek;\n    double ekold;\n    double ekdot;\n    double cek, sek;\n    double pk;\n    double pkdot;\n    double c2pk, s2pk;\n    double uk;\n    double ukdot;\n    double cuk, suk;\n    double ok;\n    double sok, cok;\n    double ik;\n    double ikdot;\n    double sik, cik;\n    double rk;\n    double rkdot;\n    double xpk, ypk;\n    double xpkdot, ypkdot;\n\n    double relativistic, OneMinusecosE, tmp;\n\n    tk = g.sec - eph.toe.sec;\n\n    if (tk > SECONDS_IN_HALF_WEEK)\n        tk -= SECONDS_IN_WEEK;\n    else if (tk<-SECONDS_IN_HALF_WEEK)\n        tk += SECONDS_IN_WEEK;\n\n    mk = eph.m0 + eph.n*tk;\n    ek = mk;\n    ekold = ek + 1.0;\n\n    OneMinusecosE = 0; // Suppress the uninitialized warning.\n    while (fabs(ek - ekold) > 1.0E-14) {\n        ekold = ek;\n        OneMinusecosE = 1.0 - eph.ecc * cos(ekold);\n        ek = ek + (mk - ekold + eph.ecc * sin(ekold)) / OneMinusecosE;\n    }\n\n    sek = sin(ek);\n    cek = cos(ek);\n\n    ekdot = eph.n / OneMinusecosE;\n\n    relativistic = -4.442807633E-10 * eph.ecc * eph.sqrta*sek;\n\n    pk = atan2(eph.sq1e2*sek, cek - eph.ecc) + eph.aop;\n    pkdot = eph.sq1e2 * ekdot / OneMinusecosE;\n\n    s2pk = sin(2.0 * pk);\n    c2pk = cos(2.0 * pk);\n\n    uk = pk + eph.cus * s2pk + eph.cuc*c2pk;\n    suk = sin(uk);\n    cuk = cos(uk);\n    ukdot = pkdot * (1.0 + 2.0 * (eph.cus * c2pk - eph.cuc * s2pk));\n\n    rk = eph.A * OneMinusecosE + eph.crc * c2pk + eph.crs*s2pk;\n    rkdot = eph.A * eph.ecc * sek * ekdot + 2.0 * pkdot * (eph.crs * c2pk - eph.crc * s2pk);\n\n    ik = eph.inc0 + eph.idot * tk + eph.cic * c2pk + eph.cis*s2pk;\n    sik = sin(ik);\n    cik = cos(ik);\n    ikdot = eph.idot + 2.0 * pkdot * (eph.cis * c2pk - eph.cic * s2pk);\n\n    xpk = rk*cuk;\n    ypk = rk*suk;\n    xpkdot = rkdot * cuk - ypk*ukdot;\n    ypkdot = rkdot * suk + xpk*ukdot;\n\n    ok = eph.omg0 + tk * eph.omgkdot - OMEGA_EARTH * eph.toe.sec;\n    sok = sin(ok);\n    cok = cos(ok);\n\n    pos[0] = xpk * cok - ypk * cik*sok;\n    pos[1] = xpk * sok + ypk * cik*cok;\n    pos[2] = ypk*sik;\n\n    tmp = ypkdot * cik - ypk * sik*ikdot;\n\n    vel[0] = -eph.omgkdot * pos[1] + xpkdot * cok - tmp*sok;\n    vel[1] = eph.omgkdot * pos[0] + xpkdot * sok + tmp*cok;\n    vel[2] = ypk * cik * ikdot + ypkdot*sik;\n\n    // Satellite clock correction\n    tk = g.sec - eph.toc.sec;\n\n    if (tk > SECONDS_IN_HALF_WEEK)\n        tk -= SECONDS_IN_WEEK;\n    else if (tk<-SECONDS_IN_HALF_WEEK)\n        tk += SECONDS_IN_WEEK;\n\n    clk[0] = eph.af0 + tk * (eph.af1 + tk * eph.af2) + relativistic - eph.tgd;\n    clk[1] = eph.af1 + 2.0 * tk * eph.af2;\n\n    return;\n}\n\n/* Compute Subframe from Ephemeris\n * eph Ephemeris of given SV\n * sbf Array of five sub-frames, 10 long words each\n */\nvoid eph2sbf(const ephem_t eph, const ionoutc_t ionoutc, const almanac_gps_t *alm, unsigned long sbf[N_SBF_PAGE][N_DWRD_SBF]) {\n    unsigned long wn;\n    unsigned long toe;\n    unsigned long toc;\n    unsigned long iode;\n    unsigned long iodc;\n    long deltan;\n    long cuc;\n    long cus;\n    long cic;\n    long cis;\n    long crc;\n    long crs;\n    unsigned long ecc;\n    unsigned long sqrta;\n    long m0;\n    long omega0;\n    long inc0;\n    long aop;\n    long omegadot;\n    long idot;\n    long af0;\n    long af1;\n    long af2;\n    long tgd;\n\n    unsigned long ura = 0UL;\n    unsigned long dataId = 1UL;\n\n    unsigned long wna;\n    unsigned long toa;\n\n    signed long alpha0, alpha1, alpha2, alpha3;\n    signed long beta0, beta1, beta2, beta3;\n    signed long A0, A1;\n    signed long dtls, dtlsf;\n    unsigned long tot, wnt, wnlsf, dn;\n\n    int sv, i;\n    unsigned long svId;\n    signed long delta_i; // Relative to i0 = 0.30 semicircles\n\n    // FIXED: This has to be the \"transmission\" week number, not for the ephemeris reference time\n    //wn = (unsigned long)(eph.toe.week%1024);\n    wn = 0UL;\n    toe = (unsigned long) (eph.toe.sec / 16.0);\n    toc = (unsigned long) (eph.toc.sec / 16.0);\n    iode = (unsigned long) (eph.iode);\n    iodc = (unsigned long) (eph.iodc);\n    deltan = (long) (eph.deltan / POW2_M43 / PI);\n    cuc = (long) (eph.cuc / POW2_M29);\n    cus = (long) (eph.cus / POW2_M29);\n    cic = (long) (eph.cic / POW2_M29);\n    cis = (long) (eph.cis / POW2_M29);\n    crc = (long) (eph.crc / POW2_M5);\n    crs = (long) (eph.crs / POW2_M5);\n    ecc = (unsigned long) (eph.ecc / POW2_M33);\n    sqrta = (unsigned long) (eph.sqrta / POW2_M19);\n    m0 = (long) (eph.m0 / POW2_M31 / PI);\n    omega0 = (long) (eph.omg0 / POW2_M31 / PI);\n    inc0 = (long) (eph.inc0 / POW2_M31 / PI);\n    aop = (long) (eph.aop / POW2_M31 / PI);\n    omegadot = (long) (eph.omgdot / POW2_M43 / PI);\n    idot = (long) (eph.idot / POW2_M43 / PI);\n    af0 = (long) (eph.af0 / POW2_M31);\n    af1 = (long) (eph.af1 / POW2_M43);\n    af2 = (long) (eph.af2 / POW2_M55);\n    tgd = (long) (eph.tgd / POW2_M31);\n\n    alpha0 = (signed long) round(ionoutc.alpha0 / POW2_M30);\n    alpha1 = (signed long) round(ionoutc.alpha1 / POW2_M27);\n    alpha2 = (signed long) round(ionoutc.alpha2 / POW2_M24);\n    alpha3 = (signed long) round(ionoutc.alpha3 / POW2_M24);\n    beta0 = (signed long) round(ionoutc.beta0 / 2048.0);\n    beta1 = (signed long) round(ionoutc.beta1 / 16384.0);\n    beta2 = (signed long) round(ionoutc.beta2 / 65536.0);\n    beta3 = (signed long) round(ionoutc.beta3 / 65536.0);\n    A0 = (signed long) round(ionoutc.A0 / POW2_M30);\n    A1 = (signed long) round(ionoutc.A1 / POW2_M50);\n    dtls = (signed long) (ionoutc.dtls);\n    tot = (unsigned long) (ionoutc.tot / 4096);\n    wnt = (unsigned long) (ionoutc.wnt % 256);\n    // TO DO: Specify scheduled leap seconds in command options\n    // 2016/12/31 (Sat) -> WNlsf = 1929, DN = 7 (http://navigationservices.agi.com/GNSSWeb/)\n    // Days are counted from 1 to 7 (Sunday is 1).\n    wnlsf = 1929 % 256;\n    dn = 7;\n    dtlsf = 18;\n\n    // Subframe 1\n    sbf[0][0] = 0x8B0000UL << 6;\n    sbf[0][1] = 0x1UL << 8;\n    sbf[0][2] = ((wn & 0x3FFUL) << 20) | (ura << 14) | (((iodc >> 8)&0x3UL) << 6);\n    sbf[0][3] = 0UL;\n    sbf[0][4] = 0UL;\n    sbf[0][5] = 0UL;\n    sbf[0][6] = (tgd & 0xFFUL) << 6;\n    sbf[0][7] = ((iodc & 0xFFUL) << 22) | ((toc & 0xFFFFUL) << 6);\n    sbf[0][8] = ((af2 & 0xFFUL) << 22) | ((af1 & 0xFFFFUL) << 6);\n    sbf[0][9] = (af0 & 0x3FFFFFUL) << 8;\n\n    // Subframe 2\n    sbf[1][0] = 0x8B0000UL << 6;\n    sbf[1][1] = 0x2UL << 8;\n    sbf[1][2] = ((iode & 0xFFUL) << 22) | ((crs & 0xFFFFUL) << 6);\n    sbf[1][3] = ((deltan & 0xFFFFUL) << 14) | (((m0 >> 24)&0xFFUL) << 6);\n    sbf[1][4] = (m0 & 0xFFFFFFUL) << 6;\n    sbf[1][5] = ((cuc & 0xFFFFUL) << 14) | (((ecc >> 24)&0xFFUL) << 6);\n    sbf[1][6] = (ecc & 0xFFFFFFUL) << 6;\n    sbf[1][7] = ((cus & 0xFFFFUL) << 14) | (((sqrta >> 24)&0xFFUL) << 6);\n    sbf[1][8] = (sqrta & 0xFFFFFFUL) << 6;\n    sbf[1][9] = (toe & 0xFFFFUL) << 14;\n\n    // Subframe 3\n    sbf[2][0] = 0x8B0000UL << 6;\n    sbf[2][1] = 0x3UL << 8;\n    sbf[2][2] = ((cic & 0xFFFFUL) << 14) | (((omega0 >> 24)&0xFFUL) << 6);\n    sbf[2][3] = (omega0 & 0xFFFFFFUL) << 6;\n    sbf[2][4] = ((cis & 0xFFFFUL) << 14) | (((inc0 >> 24)&0xFFUL) << 6);\n    sbf[2][5] = (inc0 & 0xFFFFFFUL) << 6;\n    sbf[2][6] = ((crc & 0xFFFFUL) << 14) | (((aop >> 24)&0xFFUL) << 6);\n    sbf[2][7] = (aop & 0xFFFFFFUL) << 6;\n    sbf[2][8] = (omegadot & 0xFFFFFFUL) << 6;\n    sbf[2][9] = ((iode & 0xFFUL) << 22) | ((idot & 0x3FFFUL) << 8);\n\n    // Empty all the pages of subframes 4 and 5\n    for (i = 0; i < 25; i++) {\n        svId = 0UL; // Dummy SV\n        //svId = sbf4_svId[i];\n\n        sbf[3 + i * 2][0] = 0x8B0000UL << 6; // Preamble for TLM\n        sbf[3 + i * 2][1] = 0x4UL << 8; // Subframe ID for HOW\n        sbf[3 + i * 2][2] = (dataId << 28) | (svId << 22) | ((EMPTY_WORD & 0xFFFFUL) << 6);\n        sbf[3 + i * 2][3] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[3 + i * 2][4] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[3 + i * 2][5] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[3 + i * 2][6] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[3 + i * 2][7] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[3 + i * 2][8] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[3 + i * 2][9] = (EMPTY_WORD & 0x3FFFFFUL) << 8;\n\n        //svId = sbf5_svId[i];\n\n        sbf[4 + i * 2][0] = 0x8B0000UL << 6; // Preamble for TLM\n        sbf[4 + i * 2][1] = 0x5UL << 8; // Subframe ID for HOW\n        sbf[4 + i * 2][2] = (dataId << 28) | (svId << 22) | ((EMPTY_WORD & 0xFFFFUL) << 6);\n        sbf[4 + i * 2][3] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[4 + i * 2][4] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[4 + i * 2][5] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[4 + i * 2][6] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[4 + i * 2][7] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[4 + i * 2][8] = (EMPTY_WORD & 0xFFFFFFUL) << 6;\n        sbf[4 + i * 2][9] = (EMPTY_WORD & 0x3FFFFFUL) << 8;\n    }\n\n    // Subframe 4, pages 2-5 and 7-10: almanac data for PRN 25 through 32\n    for (sv = 24; sv < MAX_SAT; sv++) {\n        if (sv >= 24 && sv <= 27) // PRN 25-28\n            i = sv - 23; // Pages 2-5 (i = 1-4)\n        else if (sv >= 28 && sv < MAX_SAT) // PRN 29-32\n            i = sv - 22; // Page 7-10 (i = 6-9)\n\n        if (alm->sv[sv].valid != 0) {\n            svId = (unsigned long) (sv + 1);\n            ecc = (unsigned long) (alm->sv[sv].e / POW2_M21);\n            toa = (unsigned long) (alm->sv[sv].toa.sec / POW2_12);\n            delta_i = (signed long) (alm->sv[sv].delta_i / POW2_M19);\n            omegadot = (signed long) (alm->sv[sv].omegadot / POW2_M38);\n            sqrta = (unsigned long) (alm->sv[sv].sqrta / POW2_M11);\n            omega0 = (signed long) (alm->sv[sv].omega0 / POW2_M23);\n            aop = (signed long) (alm->sv[sv].aop / POW2_M23);\n            m0 = (signed long) (alm->sv[sv].m0 / POW2_M23);\n            af0 = (signed long) (alm->sv[sv].af0 / POW2_M20);\n            af1 = (signed long) (alm->sv[sv].af1 / POW2_M38);\n\n            sbf[3 + i * 2][0] = 0x8B0000UL << 6; // Preamble for TLM\n            sbf[3 + i * 2][1] = 0x4UL << 8; // Subframe ID for HOW\n            sbf[3 + i * 2][2] = (dataId << 28) | (svId << 22) | ((ecc & 0xFFFFUL) << 6);\n            sbf[3 + i * 2][3] = ((toa & 0xFFUL) << 22) | ((delta_i & 0xFFFFUL) << 6);\n            sbf[3 + i * 2][4] = ((omegadot & 0xFFFFUL) << 14); // SV HEALTH = 000 (ALL DATA OK)\n            sbf[3 + i * 2][5] = ((sqrta & 0xFFFFFFUL) << 6);\n            sbf[3 + i * 2][6] = ((omega0 & 0xFFFFFFUL) << 6);\n            sbf[3 + i * 2][7] = ((aop & 0xFFFFFFUL) << 6);\n            sbf[3 + i * 2][8] = ((m0 & 0xFFFFFFUL) << 6);\n            sbf[3 + i * 2][9] = ((af0 & 0x7F8UL) << 19) | ((af1 & 0x7FFUL) << 11) | ((af0 & 0x7UL) << 8);\n        }\n    }\n\n    // Subframe 4, page 18: ionospheric and UTC data\n    if (ionoutc.vflg == true) {\n        sbf[3 + 17 * 2][0] = 0x8B0000UL << 6;\n        sbf[3 + 17 * 2][1] = 0x4UL << 8;\n        sbf[3 + 17 * 2][2] = (dataId << 28) | (sbf4_svId[17] << 22) | ((alpha0 & 0xFFUL) << 14) | ((alpha1 & 0xFFUL) << 6);\n        sbf[3 + 17 * 2][3] = ((alpha2 & 0xFFUL) << 22) | ((alpha3 & 0xFFUL) << 14) | ((beta0 & 0xFFUL) << 6);\n        sbf[3 + 17 * 2][4] = ((beta1 & 0xFFUL) << 22) | ((beta2 & 0xFFUL) << 14) | ((beta3 & 0xFFUL) << 6);\n        sbf[3 + 17 * 2][5] = (A1 & 0xFFFFFFUL) << 6;\n        sbf[3 + 17 * 2][6] = ((A0 >> 8)&0xFFFFFFUL) << 6;\n        sbf[3 + 17 * 2][7] = ((A0 & 0xFFUL) << 22) | ((tot & 0xFFUL) << 14) | ((wnt & 0xFFUL) << 6);\n        sbf[3 + 17 * 2][8] = ((dtls & 0xFFUL) << 22) | ((wnlsf & 0xFFUL) << 14) | ((dn & 0xFFUL) << 6);\n        sbf[3 + 17 * 2][9] = (dtlsf & 0xFFUL) << 22;\n    }\n\n    // Subframe 4, page 25: SV health data for PRN 25 through 32\n    sbf[3 + 24 * 2][0] = 0x8B0000UL << 6;\n    sbf[3 + 24 * 2][1] = 0x4UL << 8;\n    sbf[3 + 24 * 2][2] = (dataId << 28) | (sbf4_svId[24] << 22);\n    sbf[3 + 24 * 2][3] = 0UL;\n    sbf[3 + 24 * 2][4] = 0UL;\n    sbf[3 + 24 * 2][5] = 0UL;\n    sbf[3 + 24 * 2][6] = 0UL;\n    sbf[3 + 24 * 2][7] = 0UL;\n    sbf[3 + 24 * 2][8] = 0UL;\n    sbf[3 + 24 * 2][9] = 0UL;\n\n    // Subframe 5, page 1-24: almanac data for PRN 1 through 24\n    for (sv = 0; sv < 24; sv++) {\n        i = sv;\n\n        if (alm->sv[sv].svid != 0) {\n            svId = (unsigned long) (sv + 1);\n            ecc = (unsigned long) (alm->sv[sv].e / POW2_M21);\n            toa = (unsigned long) (alm->sv[sv].toa.sec / 4096.0);\n            delta_i = (signed long) (alm->sv[sv].delta_i / POW2_M19);\n            omegadot = (signed long) (alm->sv[sv].omegadot / POW2_M38);\n            sqrta = (unsigned long) (alm->sv[sv].sqrta / POW2_M11);\n            omega0 = (signed long) (alm->sv[sv].omega0 / POW2_M23);\n            aop = (signed long) (alm->sv[sv].aop / POW2_M23);\n            m0 = (signed long) (alm->sv[sv].m0 / POW2_M23);\n            af0 = (signed long) (alm->sv[sv].af0 / POW2_M20);\n            af1 = (signed long) (alm->sv[sv].af1 / POW2_M38);\n\n            sbf[4 + i * 2][0] = 0x8B0000UL << 6; // Preamble\n            sbf[4 + i * 2][1] = 0x5UL << 8; // Subframe ID\n            sbf[4 + i * 2][2] = (dataId << 28) | (svId << 22) | ((ecc & 0xFFFFUL) << 6);\n            sbf[4 + i * 2][3] = ((toa & 0xFFUL) << 22) | ((delta_i & 0xFFFFUL) << 6);\n            sbf[4 + i * 2][4] = ((omegadot & 0xFFFFUL) << 14); // SV HEALTH = 000 (ALL DATA OK)\n            sbf[4 + i * 2][5] = ((sqrta & 0xFFFFFFUL) << 6);\n            sbf[4 + i * 2][6] = ((omega0 & 0xFFFFFFUL) << 6);\n            sbf[4 + i * 2][7] = ((aop & 0xFFFFFFUL) << 6);\n            sbf[4 + i * 2][8] = ((m0 & 0xFFFFFFUL) << 6);\n            sbf[4 + i * 2][9] = ((af0 & 0x7F8UL) << 19) | ((af1 & 0x7FFUL) << 11) | ((af0 & 0x7UL) << 8);\n        }\n    }\n\n    // Subframe 5, page 25: SV health data for PRN 1 through 24\n    wna = (unsigned long) (eph.toe.week % 256);\n    toa = (unsigned long) (eph.toe.sec / 4096.0);\n\n    for (sv = 0; sv < MAX_SAT; sv++) {\n        if (alm->sv[sv].svid != 0) // Valid almanac is availabe\n        {\n            wna = (unsigned long) (alm->sv[sv].toa.week % 256);\n            toa = (unsigned long) (alm->sv[sv].toa.sec / 4096.0);\n            break;\n        }\n    }\n\n    sbf[4 + 24 * 2][0] = 0x8B0000UL << 6;\n    sbf[4 + 24 * 2][1] = 0x5UL << 8;\n    sbf[4 + 24 * 2][2] = (dataId << 28) | (sbf5_svId[24] << 22) | ((toa & 0xFFUL) << 14) | ((wna & 0xFFUL) << 6);\n    sbf[4 + 24 * 2][3] = 0UL;\n    sbf[4 + 24 * 2][4] = 0UL;\n    sbf[4 + 24 * 2][5] = 0UL;\n    sbf[4 + 24 * 2][6] = 0UL;\n    sbf[4 + 24 * 2][7] = 0UL;\n    sbf[4 + 24 * 2][8] = 0UL;\n    sbf[4 + 24 * 2][9] = 0UL;\n}\n\n/* Count number of bits set to 1\n * v long word in which bits are counted\n * Count of bits set to 1\n */\nstatic unsigned long countBits(unsigned long v) {\n    unsigned long c;\n    const int S[] = {1, 2, 4, 8, 16};\n    const unsigned long B[] = {\n        0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF\n    };\n\n    c = v;\n    c = ((c >> S[0]) & B[0]) + (c & B[0]);\n    c = ((c >> S[1]) & B[1]) + (c & B[1]);\n    c = ((c >> S[2]) & B[2]) + (c & B[2]);\n    c = ((c >> S[3]) & B[3]) + (c & B[3]);\n    c = ((c >> S[4]) & B[4]) + (c & B[4]);\n\n    return (c);\n}\n\nstatic int decode_wordN(unsigned int word) {\n    const unsigned int hamming[] = {\n        0xBB1F3480, 0x5D8F9A40, 0xAEC7CD00, 0x5763E680, 0x6BB1F340, 0x8B7A89C0\n    };\n    unsigned int parity = 0, w;\n    int i;\n\n    if (word & 0x40000000) word ^= 0x3FFFFFC0;\n\n    for (i = 0; i < 6; i++) {\n        parity <<= 1;\n        for (w = (word & hamming[i]) >> 6; w; w >>= 1) parity ^= w & 1;\n    }\n    if (parity != (word & 0x3F)) return 0;\n\n    //for (i=0;i<3;i++) data[i]=(unsigned char)(word>>(22-i*8));\n    return 1;\n}\n\nstatic bool validate_parityN(unsigned int W) {\n\n    // Parity stuff \n\n    static const unsigned int PARITY_25 = 0xBB1F3480;\n    static const unsigned int PARITY_26 = 0x5D8F9A40;\n    static const unsigned int PARITY_27 = 0xAEC7CD00;\n    static const unsigned int PARITY_28 = 0x5763E680;\n    static const unsigned int PARITY_29 = 0x6BB1F340;\n    static const unsigned int PARITY_30 = 0x8B7A89C0;\n\n    // Look-up table for parity of eight bit bytes\n    // (parity=0 if the number of 0s and 1s is equal, else parity=1)\n    static unsigned char byteParity[] = {\n        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\n        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\n        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\n        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\n        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,\n        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\n        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,\n        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0\n    };\n\n    // Local variables\n\n    unsigned int t, w, p;\n\n    // The sign of the data is determined by the D30* parity bit \n    // of the previous data word. If  D30* is set, invert the data \n    // bits D01..D24 to obtain the d01..d24 (but leave all other\n    // bits untouched).\n\n    w = W;\n    if (w & 0x40000000) w ^= 0x3FFFFFC0;\n\n    // Compute the parity of the sign corrected data bits d01..d24\n    // as described in the ICD-GPS-200\n\n    t = w & PARITY_25;\n    p = (byteParity[t & 0xff] ^ byteParity[(t >> 8) & 0xff] ^\n            byteParity[(t >> 16) & 0xff] ^ byteParity[(t >> 24)]);\n\n    t = w & PARITY_26;\n    p = (p << 1) |\n            (byteParity[t & 0xff] ^ byteParity[(t >> 8) & 0xff] ^\n            byteParity[(t >> 16) & 0xff] ^ byteParity[(t >> 24)]);\n\n    t = w & PARITY_27;\n    p = (p << 1) |\n            (byteParity[t & 0xff] ^ byteParity[(t >> 8) & 0xff] ^\n            byteParity[(t >> 16) & 0xff] ^ byteParity[(t >> 24)]);\n\n    t = w & PARITY_28;\n    p = (p << 1) |\n            (byteParity[t & 0xff] ^ byteParity[(t >> 8) & 0xff] ^\n            byteParity[(t >> 16) & 0xff] ^ byteParity[(t >> 24)]);\n\n    t = w & PARITY_29;\n    p = (p << 1) |\n            (byteParity[t & 0xff] ^ byteParity[(t >> 8) & 0xff] ^\n            byteParity[(t >> 16) & 0xff] ^ byteParity[(t >> 24)]);\n\n    t = w & PARITY_30;\n    p = (p << 1) |\n            (byteParity[t & 0xff] ^ byteParity[(t >> 8) & 0xff] ^\n            byteParity[(t >> 16) & 0xff] ^ byteParity[(t >> 24)]);\n\n    if ((W & 0x3f) != p) {\n        gui_status_wprintw(RED, \"%d-%u \", (W & 0x3f), p);\n    }\n    if (!decode_wordN(W)) {\n        gui_status_wprintw(RED, \"%d-%u \", (W & 0x3f), p);\n    }\n    return ((W & 0x3f) == p);\n};\n\n/* Compute the Checksum for one given word of a subframe\n * source The input data\n * nib Does this word contain non-information-bearing bits?\n * Computed Checksum\n */\nstatic unsigned long computeChecksum(unsigned long source, int nib) {\n    /*\n    Bits 31 to 30 = 2 LSBs of the previous transmitted word, D29* and D30*\n    Bits 29 to  6 = Source data bits, d1, d2, ..., d24\n    Bits  5 to  0 = Empty parity bits\n     */\n\n    /*\n    Bits 31 to 30 = 2 LSBs of the previous transmitted word, D29* and D30*\n    Bits 29 to  6 = Data bits transmitted by the SV, D1, D2, ..., D24\n    Bits  5 to  0 = Computed parity bits, D25, D26, ..., D30\n     */\n\n    /*\n                      1            2           3\n    bit    12 3456 7890 1234 5678 9012 3456 7890\n    ---    -------------------------------------\n    D25    11 1011 0001 1111 0011 0100 1000 0000\n    D26    01 1101 1000 1111 1001 1010 0100 0000\n    D27    10 1110 1100 0111 1100 1101 0000 0000\n    D28    01 0111 0110 0011 1110 0110 1000 0000\n    D29    10 1011 1011 0001 1111 0011 0100 0000\n    D30    00 1011 0111 1010 1000 1001 1100 0000\n     */\n\n    unsigned long bmask[6] = {\n        0x3B1F3480UL, 0x1D8F9A40UL, 0x2EC7CD00UL,\n        0x1763E680UL, 0x2BB1F340UL, 0x0B7A89C0UL\n    };\n\n    unsigned long D;\n    unsigned long d = source & 0x3FFFFFC0UL;\n    unsigned long D29 = (source >> 31)&0x1UL;\n    unsigned long D30 = (source >> 30)&0x1UL;\n\n    if (nib) // Non-information bearing bits for word 2 and 10\n    {\n        /*\n        Solve bits 23 and 24 to presearve parity check\n        with zeros in bits 29 and 30.\n         */\n\n        if ((D30 + countBits(bmask[4] & d)) % 2)\n            d ^= (0x1UL << 6);\n        if ((D29 + countBits(bmask[5] & d)) % 2)\n            d ^= (0x1UL << 7);\n    }\n\n    D = d;\n    if (D30)\n        D ^= 0x3FFFFFC0UL;\n\n    D |= ((D29 + countBits(bmask[0] & d)) % 2) << 5;\n    D |= ((D30 + countBits(bmask[1] & d)) % 2) << 4;\n    D |= ((D29 + countBits(bmask[2] & d)) % 2) << 3;\n    D |= ((D30 + countBits(bmask[3] & d)) % 2) << 2;\n    D |= ((D30 + countBits(bmask[4] & d)) % 2) << 1;\n    D |= ((D29 + countBits(bmask[5] & d)) % 2);\n\n    D &= 0x3FFFFFFFUL;\n    D |= (source & 0xC0000000UL); // Add D29* and D30* from source data bits\n    unsigned int W = D;\n    validate_parityN(W);\n    return (D);\n}\n\n/* Replace all 'E' exponential designators to 'D'\n * str String in which all occurrences of 'E' are replaced with *  'D'\n * len Length of input string in bytes\n * Number of characters replaced\n */\nstatic int replaceExpDesignator(char *str, int len) {\n    int i, n = 0;\n\n    for (i = 0; i < len; i++) {\n        if (str[i] == 0) {\n            break;\n        }\n\n        if (str[i] == 'D' || str[i] == 'd') {\n            n++;\n            str[i] = 'E';\n        }\n    }\n\n    return (n);\n}\n\nstatic double subGpsTime(gpstime_t g1, gpstime_t g0) {\n    double dt;\n\n    dt = g1.sec - g0.sec;\n    dt += (double) (g1.week - g0.week) * SECONDS_IN_WEEK;\n\n    return (dt);\n}\n\nstatic gpstime_t incGpsTime(gpstime_t g0, double dt) {\n    gpstime_t g1;\n\n    g1.week = g0.week;\n    g1.sec = g0.sec + dt;\n\n    g1.sec = round(g1.sec * 1000.0) / 1000.0; // Avoid rounding error\n\n    while (g1.sec >= SECONDS_IN_WEEK) {\n        g1.sec -= SECONDS_IN_WEEK;\n        g1.week++;\n    }\n\n    while (g1.sec < 0.0) {\n        g1.sec += SECONDS_IN_WEEK;\n        g1.week--;\n    }\n\n    return (g1);\n}\n\n/* Read Ephemeris data from the RINEX v2 Navigation file\n * eph Array of Output SV ephemeris data\n * fname File name of the RINEX file\n * Number of sets of ephemerides in the file\n */\nstatic int readRinex2(ephem_t eph[][MAX_SAT], ionoutc_t *ionoutc, const char *fname) {\n    struct gzFile_s *fp;\n    int ieph;\n\n    int sv;\n    char str[MAX_CHAR];\n    char tmp[20];\n    double ver = 0.0;\n\n    datetime_t t;\n    gpstime_t g;\n    gpstime_t g0;\n    double dt;\n\n    int flags = 0x0;\n\n    if (NULL == (fp = gzopen(fname, \"rt\")))\n        return (-1);\n\n    // Clear valid flag\n    for (ieph = 0; ieph < EPHEM_ARRAY_SIZE; ieph++)\n        for (sv = 0; sv < MAX_SAT; sv++)\n            eph[ieph][sv].vflg = false;\n\n    // Read header lines\n    while (1) {\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        if (strncmp(str + 60, \"COMMENT\", 7) == 0) {\n            continue;\n        } else if (strncmp(str + 60, \"END OF HEADER\", 13) == 0) {\n            break;\n        } else if (strncmp(str + 60, \"RINEX VERSION / TYPE\", 20) == 0) {\n            strncpy(tmp, str, 9);\n            tmp[9] = 0;\n            replaceExpDesignator(tmp, 9);\n            ver = atof(tmp);\n            if (ver > 3.0) {\n                gzclose(fp);\n                return -2;\n            }\n\n            if (str[20] != 'N') {\n                gzclose(fp);\n                return -3;\n            }\n        } else if (strncmp(str + 60, \"PGM / RUN BY / DATE\", 19) == 0) {\n            strncpy(rinex_date, str + 40, 20);\n            rinex_date[20] = 0;\n        } else if (strncmp(str + 60, \"ION ALPHA\", 9) == 0) {\n            strncpy(tmp, str + 2, 12);\n            tmp[12] = 0;\n            replaceExpDesignator(tmp, 12);\n            ionoutc->alpha0 = atof(tmp);\n\n            strncpy(tmp, str + 14, 12);\n            tmp[12] = 0;\n            replaceExpDesignator(tmp, 12);\n            ionoutc->alpha1 = atof(tmp);\n\n            strncpy(tmp, str + 26, 12);\n            tmp[12] = 0;\n            replaceExpDesignator(tmp, 12);\n            ionoutc->alpha2 = atof(tmp);\n\n            strncpy(tmp, str + 38, 12);\n            tmp[12] = 0;\n            replaceExpDesignator(tmp, 12);\n            ionoutc->alpha3 = atof(tmp);\n\n            flags |= 0x1;\n        } else if (strncmp(str + 60, \"ION BETA\", 8) == 0) {\n            strncpy(tmp, str + 2, 12);\n            tmp[12] = 0;\n            replaceExpDesignator(tmp, 12);\n            ionoutc->beta0 = atof(tmp);\n\n            strncpy(tmp, str + 14, 12);\n            tmp[12] = 0;\n            replaceExpDesignator(tmp, 12);\n            ionoutc->beta1 = atof(tmp);\n\n            strncpy(tmp, str + 26, 12);\n            tmp[12] = 0;\n            replaceExpDesignator(tmp, 12);\n            ionoutc->beta2 = atof(tmp);\n\n            strncpy(tmp, str + 38, 12);\n            tmp[12] = 0;\n            replaceExpDesignator(tmp, 12);\n            ionoutc->beta3 = atof(tmp);\n\n            flags |= 0x1 << 1;\n        } else if (strncmp(str + 60, \"DELTA-UTC\", 9) == 0) {\n            strncpy(tmp, str + 3, 19);\n            tmp[19] = 0;\n            replaceExpDesignator(tmp, 19);\n            ionoutc->A0 = atof(tmp);\n\n            strncpy(tmp, str + 22, 19);\n            tmp[19] = 0;\n            replaceExpDesignator(tmp, 19);\n            ionoutc->A1 = atof(tmp);\n\n            strncpy(tmp, str + 41, 9);\n            tmp[9] = 0;\n            ionoutc->tot = atoi(tmp);\n\n            strncpy(tmp, str + 50, 9);\n            tmp[9] = 0;\n            ionoutc->wnt = atoi(tmp);\n\n            if (ionoutc->tot % 4096 == 0)\n                flags |= 0x1 << 2;\n        } else if (strncmp(str + 60, \"LEAP SECONDS\", 12) == 0) {\n            strncpy(tmp, str, 6);\n            tmp[6] = 0;\n            ionoutc->dtls = atoi(tmp);\n\n            flags |= 0x1 << 3;\n        }\n    }\n\n    ionoutc->vflg = false;\n    if (flags == 0xF) // Read all Iono/UTC lines\n        ionoutc->vflg = true;\n\n    // Read ephemeris blocks\n    g0.week = -1;\n    ieph = 0;\n\n    while (1) {\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        // PRN\n        strncpy(tmp, str, 2);\n        tmp[2] = 0;\n        sv = atoi(tmp) - 1;\n\n        // EPOCH\n        strncpy(tmp, str + 3, 2);\n        tmp[2] = 0;\n        t.y = atoi(tmp) + 2000;\n\n        strncpy(tmp, str + 6, 2);\n        tmp[2] = 0;\n        t.m = atoi(tmp);\n\n        strncpy(tmp, str + 9, 2);\n        tmp[2] = 0;\n        t.d = atoi(tmp);\n\n        strncpy(tmp, str + 12, 2);\n        tmp[2] = 0;\n        t.hh = atoi(tmp);\n\n        strncpy(tmp, str + 15, 2);\n        tmp[2] = 0;\n        t.mm = atoi(tmp);\n\n        strncpy(tmp, str + 18, 4);\n        tmp[2] = 0;\n        t.sec = atof(tmp);\n\n        date2gps(&t, &g);\n\n        if (g0.week == -1)\n            g0 = g;\n\n        // Check current time of clock\n        dt = subGpsTime(g, g0);\n\n        if (dt > SECONDS_IN_HOUR) {\n            g0 = g;\n            ieph++; // a new set of ephemerides\n\n            if (ieph >= EPHEM_ARRAY_SIZE)\n                break;\n        }\n\n        // Date and time\n        eph[ieph][sv].t = t;\n\n        // SV CLK\n        eph[ieph][sv].toc = g;\n\n        strncpy(tmp, str + 22, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19); // tmp[15]='E';\n        eph[ieph][sv].af0 = atof(tmp);\n\n        strncpy(tmp, str + 41, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].af1 = atof(tmp);\n\n        strncpy(tmp, str + 60, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].af2 = atof(tmp);\n\n        // BROADCAST ORBIT - 1\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 3, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].iode = (int) atof(tmp);\n\n        strncpy(tmp, str + 22, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].crs = atof(tmp);\n\n        strncpy(tmp, str + 41, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].deltan = atof(tmp);\n\n        strncpy(tmp, str + 60, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].m0 = atof(tmp);\n\n        // BROADCAST ORBIT - 2\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 3, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].cuc = atof(tmp);\n\n        strncpy(tmp, str + 22, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].ecc = atof(tmp);\n\n        strncpy(tmp, str + 41, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].cus = atof(tmp);\n\n        strncpy(tmp, str + 60, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].sqrta = atof(tmp);\n\n        // BROADCAST ORBIT - 3\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 3, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].toe.sec = atof(tmp);\n\n        strncpy(tmp, str + 22, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].cic = atof(tmp);\n\n        strncpy(tmp, str + 41, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].omg0 = atof(tmp);\n\n        strncpy(tmp, str + 60, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].cis = atof(tmp);\n\n        // BROADCAST ORBIT - 4\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 3, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].inc0 = atof(tmp);\n\n        strncpy(tmp, str + 22, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].crc = atof(tmp);\n\n        strncpy(tmp, str + 41, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].aop = atof(tmp);\n\n        strncpy(tmp, str + 60, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].omgdot = atof(tmp);\n\n        // BROADCAST ORBIT - 5\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 3, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].idot = atof(tmp);\n\n        strncpy(tmp, str + 22, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].code = (int) atof(tmp);\n\n        strncpy(tmp, str + 41, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].toe.week = (int) atof(tmp);\n\n        strncpy(tmp, str + 60, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].flag = (int) atof(tmp);\n\n        // BROADCAST ORBIT - 6\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 3, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].sva = (int) atof(tmp);\n\n        strncpy(tmp, str + 22, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].svh = (int) atof(tmp);\n        if ((eph[ieph][sv].svh > 0) && (eph[ieph][sv].svh < 32))\n            eph[ieph][sv].svh += 32; // Set MSB to 1\n\n        strncpy(tmp, str + 41, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].tgd = atof(tmp);\n\n        strncpy(tmp, str + 60, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].iodc = (int) atof(tmp);\n\n        // BROADCAST ORBIT - 7\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 22, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].fit = atof(tmp);\n\n        // Set valid flag\n        eph[ieph][sv].vflg = true;\n\n        // Update the working variables\n        eph[ieph][sv].A = eph[ieph][sv].sqrta * eph[ieph][sv].sqrta;\n        eph[ieph][sv].n = sqrt(GM_EARTH / (eph[ieph][sv].A * eph[ieph][sv].A * eph[ieph][sv].A)) + eph[ieph][sv].deltan;\n        eph[ieph][sv].sq1e2 = sqrt(1.0 - eph[ieph][sv].ecc * eph[ieph][sv].ecc);\n        eph[ieph][sv].omgkdot = eph[ieph][sv].omgdot - OMEGA_EARTH;\n    }\n\n    gzclose(fp);\n\n    if (g0.week >= 0)\n        ieph += 1; // Number of sets of ephemerides\n\n    return (ieph);\n}\n\n/* Read Ephemeris data from the RINEX v3 Navigation file\n * eph Array of Output SV ephemeris data\n * fname File name of the RINEX file\n * Number of sets of ephemerides in the file\n */\nstatic int readRinex3(ephem_t eph[][MAX_SAT], ionoutc_t *ionoutc, const char *fname) {\n    struct gzFile_s *fp;\n    int ieph;\n\n    int sv;\n    char str[MAX_CHAR];\n    char tmp[20];\n    double ver = 0.0;\n\n    datetime_t t;\n    gpstime_t g;\n    gpstime_t g0;\n    double dt;\n\n    int flags = 0x0;\n\n    if (NULL == (fp = gzopen(fname, \"rt\")))\n        return (-1);\n\n    // Clear valid flag\n    for (ieph = 0; ieph < EPHEM_ARRAY_SIZE; ieph++)\n        for (sv = 0; sv < MAX_SAT; sv++)\n            eph[ieph][sv].vflg = false;\n\n    // Read header lines\n    while (1) {\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        if (strncmp(str + 60, \"COMMENT\", 7) == 0) {\n            continue;\n        } else if (strncmp(str + 60, \"END OF HEADER\", 13) == 0) {\n            break;\n        } else if (strncmp(str + 60, \"RINEX VERSION / TYPE\", 20) == 0) {\n            strncpy(tmp, str, 9);\n            tmp[9] = 0;\n            replaceExpDesignator(tmp, 9);\n            ver = atof(tmp);\n            if (ver < 3.0) {\n                gzclose(fp);\n                return -2;\n            }\n\n            if (str[20] != 'N' && str[40] != 'G') {\n                gzclose(fp);\n                return -3;\n            }\n        } else if (strncmp(str + 60, \"PGM / RUN BY / DATE\", 19) == 0) {\n            strncpy(rinex_date, str + 40, 20);\n            rinex_date[20] = 0;\n        } else if (strncmp(str + 60, \"IONOSPHERIC CORR\", 16) == 0) {\n            if (strncmp(str, \"GPSA\", 4) == 0) {\n                strncpy(tmp, str + 5, 12);\n                tmp[12] = 0;\n                replaceExpDesignator(tmp, 12);\n                ionoutc->alpha0 = atof(tmp);\n\n                strncpy(tmp, str + 17, 12);\n                tmp[12] = 0;\n                replaceExpDesignator(tmp, 12);\n                ionoutc->alpha1 = atof(tmp);\n\n                strncpy(tmp, str + 29, 12);\n                tmp[12] = 0;\n                replaceExpDesignator(tmp, 12);\n                ionoutc->alpha2 = atof(tmp);\n\n                strncpy(tmp, str + 41, 12);\n                tmp[12] = 0;\n                replaceExpDesignator(tmp, 12);\n                ionoutc->alpha3 = atof(tmp);\n\n                flags |= 0x1;\n            } else if (strncmp(str, \"GPSB\", 4) == 0) {\n                strncpy(tmp, str + 5, 12);\n                tmp[12] = 0;\n                replaceExpDesignator(tmp, 12);\n                ionoutc->beta0 = atof(tmp);\n\n                strncpy(tmp, str + 17, 12);\n                tmp[12] = 0;\n                replaceExpDesignator(tmp, 12);\n                ionoutc->beta1 = atof(tmp);\n\n                strncpy(tmp, str + 29, 12);\n                tmp[12] = 0;\n                replaceExpDesignator(tmp, 12);\n                ionoutc->beta2 = atof(tmp);\n\n                strncpy(tmp, str + 41, 12);\n                tmp[12] = 0;\n                replaceExpDesignator(tmp, 12);\n                ionoutc->beta3 = atof(tmp);\n\n                flags |= 0x1 << 1;\n            }\n        } else if (strncmp(str + 60, \"TIME SYSTEM CORR\", 16) == 0 && strncmp(str, \"GPUT\", 4) == 0) {\n            strncpy(tmp, str + 5, 17);\n            tmp[17] = 0;\n            replaceExpDesignator(tmp, 17);\n            ionoutc->A0 = atof(tmp);\n\n            strncpy(tmp, str + 22, 16);\n            tmp[16] = 0;\n            replaceExpDesignator(tmp, 16);\n            ionoutc->A1 = atof(tmp);\n\n            strncpy(tmp, str + 38, 7);\n            tmp[7] = 0;\n            replaceExpDesignator(tmp, 7);\n            ionoutc->tot = atoi(tmp);\n\n            strncpy(tmp, str + 45, 6);\n            tmp[6] = 0;\n            ionoutc->wnt = atoi(tmp);\n\n            if (ionoutc->tot % 4096 == 0)\n                flags |= 0x1 << 2;\n        } else if (strncmp(str + 60, \"LEAP SECONDS\", 12) == 0) {\n            strncpy(tmp, str, 6);\n            tmp[6] = 0;\n            ionoutc->dtls = atoi(tmp);\n\n            flags |= 0x1 << 3;\n        }\n    }\n\n    ionoutc->vflg = false;\n    if (flags == 0xF) // Read all Iono/UTC lines\n        ionoutc->vflg = true;\n\n    // Read ephemeris blocks\n    g0.week = -1;\n    ieph = 0;\n\n    while (1) {\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        // Check for GPS data record\n        if (str[0] != 'G') {\n            continue;\n        }\n\n        // PRN\n        strncpy(tmp, str + 1, 2);\n        tmp[2] = 0;\n        sv = atoi(tmp) - 1;\n\n        // EPOCH\n        strncpy(tmp, str + 4, 4);\n        tmp[4] = 0;\n        t.y = atoi(tmp);\n\n        strncpy(tmp, str + 9, 2);\n        tmp[2] = 0;\n        t.m = atoi(tmp);\n\n        strncpy(tmp, str + 12, 2);\n        tmp[2] = 0;\n        t.d = atoi(tmp);\n\n        strncpy(tmp, str + 15, 2);\n        tmp[2] = 0;\n        t.hh = atoi(tmp);\n\n        strncpy(tmp, str + 18, 2);\n        tmp[2] = 0;\n        t.mm = atoi(tmp);\n\n        strncpy(tmp, str + 21, 2);\n        tmp[2] = 0;\n        t.sec = (double) atoi(tmp);\n\n        date2gps(&t, &g);\n\n        if (g0.week == -1)\n            g0 = g;\n\n        // Check current time of clock\n        dt = subGpsTime(g, g0);\n\n        if (dt > SECONDS_IN_HOUR) {\n            g0 = g;\n            ieph++; // a new set of ephemerides\n\n            if (ieph >= EPHEM_ARRAY_SIZE)\n                break;\n        }\n\n        // Date and time\n        eph[ieph][sv].t = t;\n\n        // SV CLK\n        eph[ieph][sv].toc = g;\n\n        strncpy(tmp, str + 23, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].af0 = atof(tmp);\n\n        strncpy(tmp, str + 42, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].af1 = atof(tmp);\n\n        strncpy(tmp, str + 61, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].af2 = atof(tmp);\n\n        // BROADCAST ORBIT - 1\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 4, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].iode = (int) atof(tmp);\n\n        strncpy(tmp, str + 23, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].crs = atof(tmp);\n\n        strncpy(tmp, str + 42, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].deltan = atof(tmp);\n\n        strncpy(tmp, str + 61, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].m0 = atof(tmp);\n\n        // BROADCAST ORBIT - 2\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 4, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].cuc = atof(tmp);\n\n        strncpy(tmp, str + 23, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].ecc = atof(tmp);\n\n        strncpy(tmp, str + 42, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].cus = atof(tmp);\n\n        strncpy(tmp, str + 61, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].sqrta = atof(tmp);\n\n        // BROADCAST ORBIT - 3\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 4, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].toe.sec = atof(tmp);\n\n        strncpy(tmp, str + 23, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].cic = atof(tmp);\n\n        strncpy(tmp, str + 42, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].omg0 = atof(tmp);\n\n        strncpy(tmp, str + 61, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].cis = atof(tmp);\n\n        // BROADCAST ORBIT - 4\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 4, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].inc0 = atof(tmp);\n\n        strncpy(tmp, str + 23, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].crc = atof(tmp);\n\n        strncpy(tmp, str + 42, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].aop = atof(tmp);\n\n        strncpy(tmp, str + 61, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].omgdot = atof(tmp);\n\n        // BROADCAST ORBIT - 5\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 4, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].idot = atof(tmp);\n\n        strncpy(tmp, str + 23, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].code = (int) atof(tmp);\n\n        strncpy(tmp, str + 42, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].toe.week = (int) atof(tmp);\n\n        strncpy(tmp, str + 61, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].flag = (int) atof(tmp);\n\n        // BROADCAST ORBIT - 6\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        // SV accuracy not read\n\n        strncpy(tmp, str + 23, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].svh = (int) atof(tmp);\n        if ((eph[ieph][sv].svh > 0) && (eph[ieph][sv].svh < 32))\n            eph[ieph][sv].svh += 32; // Set MSB to 1\n\n        strncpy(tmp, str + 42, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].tgd = atof(tmp);\n\n        strncpy(tmp, str + 61, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].iodc = (int) atof(tmp);\n\n        // BROADCAST ORBIT - 7\n        if (NULL == gzgets(fp, str, MAX_CHAR))\n            break;\n\n        strncpy(tmp, str + 23, 19);\n        tmp[19] = 0;\n        replaceExpDesignator(tmp, 19);\n        eph[ieph][sv].fit = atof(tmp);\n\n        // Set valid flag\n        eph[ieph][sv].vflg = true;\n\n        // Update the working variables\n        eph[ieph][sv].A = eph[ieph][sv].sqrta * eph[ieph][sv].sqrta;\n        eph[ieph][sv].n = sqrt(GM_EARTH / (eph[ieph][sv].A * eph[ieph][sv].A * eph[ieph][sv].A)) + eph[ieph][sv].deltan;\n        eph[ieph][sv].sq1e2 = sqrt(1.0 - eph[ieph][sv].ecc * eph[ieph][sv].ecc);\n        eph[ieph][sv].omgkdot = eph[ieph][sv].omgdot - OMEGA_EARTH;\n    }\n\n    gzclose(fp);\n\n    if (g0.week >= 0)\n        ieph += 1; // Number of sets of ephemerides\n\n    return (ieph);\n}\n\nstatic double ionosphericDelay(const ionoutc_t *ionoutc, gpstime_t g, double *llh, double *azel) {\n    double iono_delay = 0.0;\n    double E, phi_u, lam_u, F;\n\n    if (ionoutc->enable == false)\n        return (0.0); // No ionospheric delay\n\n    E = azel[1] / PI;\n    phi_u = llh[0] / PI;\n    lam_u = llh[1] / PI;\n\n    // Obliquity factor\n    F = 1.0 + 16.0 * pow((0.53 - E), 3.0);\n\n    if (ionoutc->vflg == false)\n        iono_delay = F * 5.0e-9 * SPEED_OF_LIGHT;\n    else {\n        double t, psi, phi_i, lam_i, phi_m, phi_m2, phi_m3;\n        double AMP, PER, X, X2, X4;\n\n        // Earth's central angle between the user position and the earth projection of\n        // ionospheric intersection point (semi-circles)\n        psi = 0.0137 / (E + 0.11) - 0.022;\n\n        // Geodetic latitude of the earth projection of the ionospheric intersection point\n        // (semi-circles)\n        phi_i = phi_u + psi * cos(azel[0]);\n        if (phi_i > 0.416)\n            phi_i = 0.416;\n        else if (phi_i<-0.416)\n            phi_i = -0.416;\n\n        // Geodetic longitude of the earth projection of the ionospheric intersection point\n        // (semi-circles)\n        lam_i = lam_u + psi * sin(azel[0]) / cos(phi_i * PI);\n\n        // Geomagnetic latitude of the earth projection of the ionospheric intersection\n        // point (mean ionospheric height assumed 350 km) (semi-circles)\n        phi_m = phi_i + 0.064 * cos((lam_i - 1.617) * PI);\n        phi_m2 = phi_m*phi_m;\n        phi_m3 = phi_m2*phi_m;\n\n        AMP = ionoutc->alpha0 + ionoutc->alpha1 * phi_m\n                + ionoutc->alpha2 * phi_m2 + ionoutc->alpha3*phi_m3;\n        if (AMP < 0.0)\n            AMP = 0.0;\n\n        PER = ionoutc->beta0 + ionoutc->beta1 * phi_m\n                + ionoutc->beta2 * phi_m2 + ionoutc->beta3*phi_m3;\n        if (PER < 72000.0)\n            PER = 72000.0;\n\n        // Local time (sec)\n        t = SECONDS_IN_DAY / 2.0 * lam_i + g.sec;\n        while (t >= SECONDS_IN_DAY)\n            t -= SECONDS_IN_DAY;\n        while (t < 0)\n            t += SECONDS_IN_DAY;\n\n        // Phase (radians)\n        X = 2.0 * PI * (t - 50400.0) / PER;\n\n        if (fabs(X) < 1.57) {\n            X2 = X*X;\n            X4 = X2*X2;\n            iono_delay = F * (5.0e-9 + AMP * (1.0 - X2 / 2.0 + X4 / 24.0)) * SPEED_OF_LIGHT;\n        } else\n            iono_delay = F * 5.0e-9 * SPEED_OF_LIGHT;\n    }\n\n    return (iono_delay);\n}\n\n/* Compute range between a satellite and the receiver\n * rho The computed range\n * eph Ephemeris data of the satellite\n * g GPS time at time of receiving the signal\n * xyz position of the receiver\n */\nstatic void computeRange(range_t *rho, ephem_t eph, ionoutc_t *ionoutc, gpstime_t g, double xyz[]) {\n    double pos[3], vel[3], clk[2];\n    double los[3];\n    double tau;\n    double range, rate;\n    double xrot, yrot;\n\n    double llh[3], neu[3];\n    double tmat[3][3];\n\n    // SV position at time of the pseudorange observation.\n    satpos(eph, g, pos, vel, clk);\n\n    // Receiver to satellite vector and light-time.\n    subVect(los, pos, xyz);\n    tau = normVect(los) / SPEED_OF_LIGHT;\n\n    // Extrapolate the satellite position backwards to the transmission time.\n    pos[0] -= vel[0] * tau;\n    pos[1] -= vel[1] * tau;\n    pos[2] -= vel[2] * tau;\n\n    // Earth rotation correction. The change in velocity can be neglected.\n    xrot = pos[0] + pos[1] * OMEGA_EARTH*tau;\n    yrot = pos[1] - pos[0] * OMEGA_EARTH*tau;\n    pos[0] = xrot;\n    pos[1] = yrot;\n\n    // New observer to satellite vector and satellite range.\n    subVect(los, pos, xyz);\n    range = normVect(los);\n    rho->d = range;\n\n    // Pseudorange.\n    rho->range = range - SPEED_OF_LIGHT * clk[0];\n\n    // Relative velocity of SV and receiver.\n    rate = dotProd(vel, los) / range;\n\n    // Pseudorange rate.\n    rho->rate = rate; // - SPEED_OF_LIGHT*clk[1];\n\n    // Time of application.\n    rho->g = g;\n\n    // Azimuth and elevation angles.\n    xyz2llh(xyz, llh);\n    ltcmat(llh, tmat);\n    ecef2neu(los, tmat, neu);\n    neu2azel(rho->azel, neu);\n\n    // Add ionospheric delay\n    rho->iono_delay = ionosphericDelay(ionoutc, g, llh, rho->azel);\n    rho->range += rho->iono_delay;\n}\n\n/* Compute the code phase for a given channel (satellite)\n * chan Channel on which we operate (is updated)\n * rho1 Current range, after \\a dt has expired\n * dt delta-t (time difference) in seconds\n */\nstatic void computeCodePhase(channel_t *chan, range_t rho1, double dt) {\n    double ms;\n    int ims;\n    double rhorate;\n\n    // Pseudorange rate.\n    rhorate = (rho1.range - chan->rho0.range) / dt;\n\n    // Carrier and code frequency.\n    chan->f_carr = -rhorate / LAMBDA_L1;\n    chan->f_code = CODE_FREQ + chan->f_carr*CARR_TO_CODE;\n\n    // Initial code phase and data bit counters.\n    ms = ((subGpsTime(chan->rho0.g, chan->g0) + 6.0) - chan->rho0.range / SPEED_OF_LIGHT)*1000.0;\n\n    ims = (int) ms;\n    chan->code_phase = (ms - (double) ims) * CA_SEQ_LEN; // in chip\n\n    chan->iword = ims / 600; // 1 word = 30 bits = 600 ms\n    ims -= chan->iword * 600;\n\n    chan->ibit = ims / 20; // 1 bit = 20 code = 20 ms\n    ims -= chan->ibit * 20;\n\n    chan->icode = ims; // 1 code = 1 ms\n\n    chan->codeCA = chan->ca[(int) chan->code_phase]*2 - 1;\n    chan->dataBit = (int) ((chan->dwrd[chan->iword]>>(29 - chan->ibit)) & 0x1UL)*2 - 1;\n\n    // Save current pseudorange\n    chan->rho0 = rho1;\n}\n\nvoid generateNavMsg(gpstime_t g, channel_t *chan, int init) {\n    int iwrd, isbf;\n    gpstime_t g0;\n    unsigned long wn, tow;\n    unsigned sbfwrd;\n    unsigned long prevwrd;\n    int nib;\n\n    g0.week = g.week;\n    g0.sec = (double) (((unsigned long) (g.sec + 0.5)) / 30UL) * 30.0; // Align with the full frame length = 30 sec\n    chan->g0 = g0; // Data bit reference time\n\n    wn = (unsigned long) (g0.week % 1024);\n    tow = ((unsigned long) g0.sec) / 6UL;\n\n    // Initialize the subframe 5\n    if (init == 1) {\n        prevwrd = 0UL;\n\n        for (iwrd = 0; iwrd < N_DWRD_SBF; iwrd++) {\n            sbfwrd = chan->sbf[4 + chan->ipage * 2][iwrd];\n\n            // Add TOW-count message into HOW\n            if (iwrd == 1)\n                sbfwrd |= ((tow & 0x1FFFFUL) << 13);\n\n            // Compute checksum\n            sbfwrd |= (prevwrd << 30) & 0xC0000000UL; // 2 LSBs of the previous transmitted word\n            nib = ((iwrd == 1) || (iwrd == 9)) ? 1 : 0; // Non-information bearing bits for word 2 and 10\n            chan->dwrd[iwrd] = computeChecksum(sbfwrd, nib);\n\n            prevwrd = chan->dwrd[iwrd];\n        }\n    } else {\n        for (iwrd = 0; iwrd < N_DWRD_SBF; iwrd++) {\n            chan->dwrd[iwrd] = chan->dwrd[N_DWRD_SBF * N_SBF + iwrd];\n\n            prevwrd = chan->dwrd[iwrd];\n        }\n    }\n\n    // Generate subframe words\n    for (isbf = 0; isbf < N_SBF; isbf++) {\n        tow++;\n\n        for (iwrd = 0; iwrd < N_DWRD_SBF; iwrd++) {\n            if (isbf < 3) // Subframes 1-3\n                sbfwrd = chan->sbf[isbf][iwrd];\n            else if (isbf == 3) // Subframe 4\n                sbfwrd = chan->sbf[3 + chan->ipage * 2][iwrd];\n            else // Subframe 5 \n                sbfwrd = chan->sbf[4 + chan->ipage * 2][iwrd];\n\n            // Add transmission week number to Subframe 1\n            if ((isbf == 0)&&(iwrd == 2))\n                sbfwrd |= (wn & 0x3FFUL) << 20;\n\n            // Add TOW-count message into HOW\n            if (iwrd == 1)\n                sbfwrd |= ((tow & 0x1FFFFUL) << 13);\n\n            // Compute checksum\n            sbfwrd |= (prevwrd << 30) & 0xC0000000UL; // 2 LSBs of the previous transmitted word\n            nib = ((iwrd == 1) || (iwrd == 9)) ? 1 : 0; // Non-information bearing bits for word 2 and 10\n            chan->dwrd[(isbf + 1) * N_DWRD_SBF + iwrd] = computeChecksum(sbfwrd, nib);\n\n            prevwrd = chan->dwrd[(isbf + 1) * N_DWRD_SBF + iwrd];\n        }\n    }\n\n    // Move to the next pages\n    chan->ipage++;\n    if (chan->ipage >= 25)\n        chan->ipage = 0;\n}\n\nstatic int checkSatVisibility(ephem_t eph, gpstime_t g, double *xyz, double elvMask, double *azel) {\n    double llh[3], neu[3];\n    double pos[3], vel[3], clk[3], los[3];\n    double tmat[3][3];\n\n    if (eph.vflg == false)\n        return (-1); // Invalid\n\n    xyz2llh(xyz, llh);\n    ltcmat(llh, tmat);\n\n    satpos(eph, g, pos, vel, clk);\n    subVect(los, pos, xyz);\n    ecef2neu(los, tmat, neu);\n    neu2azel(azel, neu);\n\n    if (azel[1] * R2D > elvMask)\n        return (1); // Visible\n    // else\n    return (0); // Invisible\n}\n\nstatic int allocateChannel(channel_t *chan, almanac_gps_t *alm, ephem_t *eph, ionoutc_t ionoutc, gpstime_t grx, double *xyz, double elvMask) {\n    NOTUSED(elvMask);\n    int nsat = 0;\n    int i, sv;\n    double azel[2];\n\n    range_t rho;\n    double ref[3] = {0.0};\n    double r_ref, r_xyz;\n    double phase_ini;\n\n    for (sv = 0; sv < MAX_SAT; sv++) {\n        if (checkSatVisibility(eph[sv], grx, xyz, 0.0, azel) == 1) {\n            nsat++; // Number of visible satellites\n\n            if (allocatedSat[sv] == -1) // Visible but not allocated\n            {\n                // Allocated new satellite\n                for (i = 0; i < MAX_CHAN; i++) {\n                    if (chan[i].prn == 0) {\n                        // Initialize channel\n                        chan[i].prn = sv + 1;\n                        chan[i].azel[0] = azel[0];\n                        chan[i].azel[1] = azel[1];\n\n                        // C/A code generation\n                        codegen(chan[i].ca, chan[i].prn);\n\n                        // Generate subframe\n                        eph2sbf(eph[sv], ionoutc, alm, chan[i].sbf);\n\n                        // Generate navigation message\n                        generateNavMsg(grx, &chan[i], 1);\n\n                        // Initialize pseudorange\n                        computeRange(&rho, eph[sv], &ionoutc, grx, xyz);\n                        chan[i].rho0 = rho;\n\n                        // Initialize carrier phase\n                        r_xyz = rho.range;\n\n                        computeRange(&rho, eph[sv], &ionoutc, grx, ref);\n                        r_ref = rho.range;\n\n                        phase_ini = (2.0 * r_ref - r_xyz) / LAMBDA_L1;\n#ifdef FLOAT_CARR_PHASE\n                        chan[i].carr_phase = phase_ini - floor(phase_ini);\n#else\n                        phase_ini -= floor(phase_ini);\n                        chan[i].carr_phase = (unsigned int) (512.0 * 65536.0 * phase_ini);\n#endif\n                        // Done.\n                        break;\n                    }\n                }\n\n                // Set satellite allocation channel\n                if (i < MAX_CHAN)\n                    allocatedSat[sv] = i;\n            }\n        } else if (allocatedSat[sv] >= 0) // Not visible but allocated\n        {\n            // Clear channel\n            chan[allocatedSat[sv]].prn = 0;\n\n            // Clear satellite allocation flag\n            allocatedSat[sv] = -1;\n        }\n    }\n\n    return (nsat);\n}\n\nstatic size_t fwrite_rinex(void *buffer, size_t size, size_t nmemb, void *stream) {\n    struct ftp_file *out = (struct ftp_file *) stream;\n    if (out && !out->stream) {\n        /* open file for writing */\n        out->stream = fopen(out->filename, \"wb\");\n        if (!out->stream)\n            return -1; /* failure, can't open file to write */\n    }\n    return fwrite(buffer, size, nmemb, out->stream);\n}\n\n/* Read the list of user motions from the input file\n * xyz Output array of ECEF vectors for user motion\n * filename File name of the text input file\n * Returns number of user data motion records read, -1 on error\n */\nstatic int readUserMotion(double xyz[USER_MOTION_SIZE][3], const char *filename) {\n    FILE *fp;\n    int numd;\n    char str[MAX_CHAR];\n    double t, x, y, z;\n\n    if (NULL == (fp = fopen(filename, \"rt\")))\n        return (-1);\n\n    for (numd = 0; numd < USER_MOTION_SIZE; numd++) {\n        if (fgets(str, MAX_CHAR, fp) == NULL)\n            break;\n\n        if (EOF == sscanf(str, \"%lf,%lf,%lf,%lf\", &t, &x, &y, &z)) // Read CSV line\n            break;\n\n        xyz[numd][0] = x;\n        xyz[numd][1] = y;\n        xyz[numd][2] = z;\n    }\n\n    fclose(fp);\n\n    return (numd);\n}\n\n/*\n * \n */\nvoid *gps_thread_ep(void *arg) {\n    simulator_t *simulator = (simulator_t *) (arg);\n\n    ephem_t eph[EPHEM_ARRAY_SIZE][MAX_SAT];\n    channel_t chan[MAX_CHAN];\n\n    datetime_t ttmp;\n    datetime_t tmin, tmax;\n    gpstime_t gmin, gmax;\n    gpstime_t grx;\n    gpstime_t g0;\n    gpstime_t gtmp;\n    g0.week = -1; // Invalid start time\n    date2gps(&simulator->start, &g0);\n\n    double elvmask = 0.0; // in degree\n    const double delt = 1.0 / (double) TX_SAMPLERATE;\n    double llh[3];\n    double gain[MAX_CHAN];\n    double path_loss;\n    double ant_gain;\n    double ant_pat[37];\n    double dt;\n\n    ionoutc_t ionoutc;\n    ionoutc.enable = simulator->ionosphere_enable;\n\n    bool sat_simulated[33] = {false};\n\n    int start_y = 4; // Row to start output in LS_FIX window/panel\n    int ibs; // boresight angle index    \n    int igrx;\n    int sv;\n    int neph, ieph;\n    int i;\n    int ip, qp;\n    int iTable;\n    int isamp;\n    short *iq_buff = NULL;\n\n    // Allocate user motion array\n    double (*xyz)[3] = malloc(sizeof (double[USER_MOTION_SIZE][3]));\n    if (xyz == NULL) {\n        gui_status_wprintw(RED, \"Failed to allocate user motion memory.\\n\");\n        goto end_gps_thread;\n    }\n\n    // Initialize user motion array\n    // with current location/position\n    int iumd = 0;\n    int numd = simulator->duration;\n    double tmat[3][3];\n    double neu[3];\n\n    // Set user location\n    llh[0] = simulator->location.lat / R2D;\n    llh[1] = simulator->location.lon / R2D;\n    llh[2] = simulator->location.height;\n    llh2xyz(llh, xyz[0]);\n    ltcmat(llh, tmat);\n\n    if (!simulator->target.valid) {\n        // No target position given, use location\n        simulator->target.lat = simulator->location.lat;\n        simulator->target.lon = simulator->location.lon;\n        simulator->target.height = simulator->location.height;\n    } else {\n        // Set target position as simulation start\n        // Given as distance and bearing from user location in -t option\n        neu[0] = simulator->target.distance * cos((simulator->target.bearing / 1000) / R2D);\n        neu[1] = simulator->target.distance * sin((simulator->target.bearing / 1000) / R2D);\n        neu[2] = simulator->target.height;\n        xyz[0][0] += tmat[0][0] * neu[0] + tmat[1][0] * neu[1] + tmat[2][0] * neu[2];\n        xyz[0][1] += tmat[0][1] * neu[0] + tmat[1][1] * neu[1] + tmat[2][1] * neu[2];\n        xyz[0][2] += tmat[0][2] * neu[0] + tmat[1][2] * neu[1] + tmat[2][2] * neu[2];\n    }\n\n    for (iumd = 1; iumd < numd; iumd++) {\n        xyz[iumd][0] = xyz[0][0];\n        xyz[iumd][1] = xyz[0][1];\n        xyz[iumd][2] = xyz[0][2];\n    }\n\n    gui_show_location(&simulator->location);\n\n    CURL *curl;\n    CURLcode curl_code = CURLE_GOT_NOTHING;\n    struct ftp_file ftp = {\n        RINEX2_FILE_NAME,\n        NULL\n    };\n\n    /* On a multi-core CPU we run the main thread and reader thread on different cores.\n     * Try sticking the main thread to core 2\n     */\n    thread_to_core(2);\n    set_thread_name(\"gps-thread\");\n\n    if ((simulator->nav_file_name == NULL) && (simulator->use_ftp == false)) {\n        gui_status_wprintw(RED, \"GPS ephemeris file is not specified.\\n\");\n        goto end_gps_thread;\n    }\n\n    ////////////////////////////////////////////////////////////\n    // Read ephemeris\n    ////////////////////////////////////////////////////////////\n    if (simulator->use_ftp) {\n        time_t t = time(NULL);\n        struct tm *tm = gmtime(&t);\n        char* url = malloc(NAME_MAX);\n        int station_index = 0;\n        // Use RINEX v2 by default or v3 on request\n        const stations_t *pstation = stations_v2;\n        if (simulator->use_rinex3) {\n            pstation = stations_v3;\n        }\n\n        // Get number of stations available, find index for given one\n        for (int s = 0; pstation[s].id_v2 != NULL; s++) {\n            // Station id given, get index\n            if (simulator->station_id != NULL) {\n                if (strncmp(pstation[s].id_v2, simulator->station_id, 4) == 0 || strncmp(pstation[s].id_v3, simulator->station_id, 9) == 0) {\n                    break;\n                }\n            }\n            station_index += 1;\n        }\n\n        // Pick a random station if none given\n        if (simulator->station_id == NULL) {\n            srand((unsigned int) g0.sec);\n            station_index = rand() % station_index;\n        }\n        // Check that we have a picked a valid station\n        // Take the first one when invalid\n        if (pstation[station_index].id_v2 == NULL) {\n            station_index = 0;\n        }\n\n        gui_status_wprintw(GREEN, \"Pulling RINEX v%u from station: %s\\n\", (simulator->use_rinex3) ? 3 : 2, pstation[station_index].name);\n\n        // We fetch data from previous hour because the actual hour is still in progress\n        tm->tm_hour -= 1;\n        if (tm->tm_hour < 0) {\n            tm->tm_hour = 23;\n        }\n\n        // Compose FTP URL\n        snprintf(url, NAME_MAX, RINEX_FTP_URL RINEX_FTP_FILE, (simulator->use_rinex3) ? RINEX3_SUBFOLDER : RINEX2_SUBFOLDER,\n                tm->tm_yday + 1, tm->tm_hour, pstation[station_index].id_v2, tm->tm_yday + 1, 'a' + tm->tm_hour, tm->tm_year - 100);\n\n        curl_global_init(CURL_GLOBAL_DEFAULT);\n        curl = curl_easy_init();\n        if (curl) {\n            curl_easy_setopt(curl, CURLOPT_URL, url);\n            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_rinex);\n            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftp);\n            curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_NONE);\n            if (0 /*simulator->show_verbose*/) {\n                curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);\n            } else {\n                curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);\n            }\n            curl_easy_setopt(curl, CURLOPT_USERPWD, \"anonymous:anonymous\");\n            curl_code = curl_easy_perform(curl);\n            curl_easy_cleanup(curl);\n        }\n\n        if (ftp.stream)\n            fclose(ftp.stream);\n\n        free(url);\n        curl_global_cleanup();\n\n        if (curl_code != CURLE_OK) {\n            switch (curl_code) {\n                case CURLE_REMOTE_FILE_NOT_FOUND:\n                    gui_status_wprintw(RED, \"Curl error: Ephemeris file not found!\\n\");\n                    break;\n                default:\n                    gui_status_wprintw(RED, \"Curl error: %d\\n\", curl_code);\n                    break;\n            }\n            goto end_gps_thread;\n        }\n    }\n\n    if (simulator->use_rinex3) {\n        neph = readRinex3(eph, &ionoutc, simulator->nav_file_name);\n    } else {\n        neph = readRinex2(eph, &ionoutc, simulator->nav_file_name);\n    }\n\n    if (neph == 0) {\n        gui_status_wprintw(RED, \"No ephemeris available.\\n\");\n        goto end_gps_thread;\n    }\n\n    if (simulator->show_verbose) {\n        if (ionoutc.vflg && ionoutc.enable) {\n            gui_mvwprintw(LS_FIX, 14, 40, \"ION ALPHA %12.3e %12.3e %12.3e %12.3e\",\n                    ionoutc.alpha0, ionoutc.alpha1, ionoutc.alpha2, ionoutc.alpha3);\n            gui_mvwprintw(LS_FIX, 15, 40, \"ION BETA  %12.3e %12.3e %12.3e %12.3e\",\n                    ionoutc.beta0, ionoutc.beta1, ionoutc.beta2, ionoutc.beta3);\n            gui_mvwprintw(LS_FIX, 16, 40, \"DELTA UTC %12.3e %12.3e %9d  %9d\",\n                    ionoutc.A0, ionoutc.A1, ionoutc.tot, ionoutc.wnt);\n            gui_mvwprintw(LS_FIX, 17, 40, \"LEAP SECONDS %d\", ionoutc.dtls);\n        } else {\n            gui_mvwprintw(LS_FIX, 14, 40, \"Ionospheric data invalid or disabled!\");\n        }\n    }\n\n    // Read user motion file if any\n    if (simulator->motion_file_name != NULL) {\n        numd = readUserMotion(xyz, simulator->motion_file_name);\n        if (numd <= 0) {\n            gui_status_wprintw(RED, \"Failed to read user motion file.\\n\");\n            goto end_gps_thread;\n        }\n        gui_status_wprintw(GREEN, \"%u user motion points applied.\\n\", numd);\n        if (numd > simulator->duration) {\n            numd = simulator->duration;\n        }\n    }\n\n    for (sv = 0; sv < MAX_SAT; sv++) {\n        if (eph[0][sv].vflg == true) {\n            gmin = eph[0][sv].toc;\n            tmin = eph[0][sv].t;\n            break;\n        }\n    }\n\n    gmax.sec = 0;\n    gmax.week = 0;\n    tmax.sec = 0;\n    tmax.mm = 0;\n    tmax.hh = 0;\n    tmax.d = 0;\n    tmax.m = 0;\n    tmax.y = 0;\n    for (sv = 0; sv < MAX_SAT; sv++) {\n        if (eph[neph - 1][sv].vflg == true) {\n            gmax = eph[neph - 1][sv].toc;\n            tmax = eph[neph - 1][sv].t;\n            break;\n        }\n    }\n\n    if (g0.week >= 0) // Scenario start time has been set.\n    {\n        if (simulator->time_overwrite == true) {\n            double dsec;\n\n            gtmp.week = g0.week;\n            gtmp.sec = (double) (((int) (g0.sec)) / 7200)*7200.0;\n\n            dsec = subGpsTime(gtmp, gmin);\n\n            // Overwrite the UTC reference week number\n            ionoutc.wnt = gtmp.week;\n            ionoutc.tot = (int) gtmp.sec;\n\n            // Iono/UTC parameters may no longer valid\n            //ionoutc.vflg = FALSE;\n\n            // Overwrite the TOC and TOE to the scenario start time\n            for (sv = 0; sv < MAX_SAT; sv++) {\n                for (i = 0; i < neph; i++) {\n                    if (eph[i][sv].vflg == true) {\n                        gtmp = incGpsTime(eph[i][sv].toc, dsec);\n                        gps2date(&gtmp, &ttmp);\n                        eph[i][sv].toc = gtmp;\n                        eph[i][sv].t = ttmp;\n\n                        gtmp = incGpsTime(eph[i][sv].toe, dsec);\n                        eph[i][sv].toe = gtmp;\n                    }\n                }\n            }\n        } else {\n            if (subGpsTime(g0, gmin) < 0.0 || subGpsTime(gmax, g0) < 0.0) {\n                gui_status_wprintw(RED, \"Invalid start time.\\n\");\n                gui_status_wprintw(RED, \"tmin = %4d/%02d/%02d,%02d:%02d:%02.0f (%d:%.0f)\\n\",\n                        tmin.y, tmin.m, tmin.d, tmin.hh, tmin.mm, tmin.sec,\n                        gmin.week, gmin.sec);\n                gui_status_wprintw(RED, \"tmax = %4d/%02d/%02d,%02d:%02d:%02.0f (%d:%.0f)\\n\",\n                        tmax.y, tmax.m, tmax.d, tmax.hh, tmax.mm, tmax.sec,\n                        gmax.week, gmax.sec);\n                goto end_gps_thread;\n            }\n        }\n    } else {\n        g0 = gmin;\n        simulator->start = tmin;\n    }\n\n    gui_mvwprintw(LS_FIX, 8, 40, \"RINEX date:      %s\", rinex_date);\n    gui_mvwprintw(LS_FIX, 10, 40, \"Start time:      %4d/%02d/%02d,%02d:%02d:%02.0f (%d:%.0f)\",\n            simulator->start.y, simulator->start.m, simulator->start.d, simulator->start.hh, simulator->start.mm, simulator->start.sec, g0.week, g0.sec);\n    if (simulator->show_verbose) {\n        gui_mvwprintw(LS_FIX, 11, 40, \"Simulation time: \");\n    }\n    gui_mvwprintw(LS_FIX, 7, 40, \"Duration:        %.1fs\", ((double) numd) / 10.0);\n\n    // Select the current set of ephemerides\n    ieph = -1;\n\n    for (i = 0; i < neph; i++) {\n        for (sv = 0; sv < MAX_SAT; sv++) {\n            if (eph[i][sv].vflg == true) {\n                dt = subGpsTime(g0, eph[i][sv].toc);\n                if (dt >= -SECONDS_IN_HOUR && dt < SECONDS_IN_HOUR) {\n                    ieph = i;\n                    break;\n                }\n            }\n        }\n\n        if (ieph >= 0) // ieph has been set\n            break;\n    }\n\n    if (ieph == -1) {\n        gui_status_wprintw(RED, \"No current set of ephemerides has been found.\\n\");\n        goto end_gps_thread;\n    }\n\n    ////////////////////////////////////////////////////////////\n    // Read almanac\n    ////////////////////////////////////////////////////////////\n\n    almanac_gps_t *alm = almanac_init();\n    if (simulator->almanac_enable) {\n        if (simulator->use_ftp) {\n            curl_code = almanac_download();\n        } else {\n            curl_code = almanac_read_file();\n        }\n\n        if (curl_code != CURLE_OK) {\n            switch (curl_code) {\n                case CURLE_REMOTE_FILE_NOT_FOUND:\n                    gui_status_wprintw(RED, \"Almanac file not found!\\n\");\n                    break;\n                case CURLE_READ_ERROR:\n                    gui_status_wprintw(RED, \"Error reading almanac file!\\n\");\n                    break;\n                default:\n                    gui_status_wprintw(RED, \"Almanac error, code: %d\\n\", curl_code);\n                    break;\n            }\n        }\n    }\n\n    if (simulator->almanac_enable && alm->valid) {\n        gtmp.sec = 0.0;\n        gtmp.week = 0;\n        // Check TOA\n        for (sv = 0; sv < MAX_SAT; sv++) {\n            if (alm->sv[sv].valid != 0) // Valid almanac\n            {\n                gtmp = alm->sv[sv].toa;\n                dt = subGpsTime(alm->sv[sv].toa, g0);\n                if (dt < (-4.0 * SECONDS_IN_WEEK) || dt > (4.0 * SECONDS_IN_WEEK)) {\n                    gui_status_wprintw(RED, \"Invalid time of almanac.\\n\");\n                    goto end_gps_thread;\n                }\n            }\n        }\n        gps2date(&gtmp, &ttmp);\n        gui_mvwprintw(LS_FIX, 9, 40, \"Almanac date:    %4d/%02d/%02d,%02d:%02d:%02.0f\",\n                ttmp.y, ttmp.m, ttmp.d, ttmp.hh, ttmp.mm, ttmp.sec);\n    } else {\n        gui_mvwprintw(LS_FIX, 9, 40, \"Almanac date:    Disabled or invalid.\");\n    }\n\n    ////////////////////////////////////////////////////////////\n    // Initialize channels\n    ////////////////////////////////////////////////////////////\n\n    // Clear all channels\n    for (i = 0; i < MAX_CHAN; i++)\n        chan[i].prn = 0;\n\n    // Clear satellite allocation flag\n    for (sv = 0; sv < MAX_SAT; sv++)\n        allocatedSat[sv] = -1;\n\n    // Initial reception time\n    grx = incGpsTime(g0, 0.0);\n\n    // Allocate visible satellites\n    allocateChannel(chan, alm, eph[ieph], ionoutc, grx, xyz[0], elvmask);\n\n    for (i = 0; i < MAX_CHAN; i++) {\n        if (chan[i].prn > 0) {\n            gui_mvwprintw(LS_FIX, start_y++, 1, \"%02d %6.1f %5.1f %11.1f %5.1f\", chan[i].prn,\n                    chan[i].azel[0] * R2D, chan[i].azel[1] * R2D, chan[i].rho0.d, chan[i].rho0.iono_delay);\n        }\n\n        sat_simulated[chan[i].prn] = true;\n    }\n    gui_mvwprintw(LS_FIX, 3, 40, \"Nav: %02d satellites\", start_y - 4);\n\n    // Receiver antenna gain pattern\n    for (i = 0; i < 37; i++)\n        ant_pat[i] = pow(10.0, -ant_pat_db[i] / 20.0);\n\n    // Update receiver time\n    grx = incGpsTime(grx, 0.1);\n\n    // Create IQ buffer.\n    iq_buff = calloc(IQ_BUFFER_SIZE, 2);\n\n    // Aquire first fifo block for transfer buffer\n    struct iq_buf *iq = fifo_acquire();\n\n    ////////////////////////////////////////////////////////////\n    // Generate baseband signals\n    ////////////////////////////////////////////////////////////\n    for (iumd = 1; iumd < numd; iumd++) {\n        if (simulator->gps_thread_exit) {\n            break;\n        }\n\n        // Signal GPS init done and running\n        if (simulator->gps_thread_running == false) {\n            simulator->gps_thread_running = true;\n            pthread_cond_signal(&(simulator->gps_init_done));\n        }\n\n        if (simulator->interactive_mode) {\n            // Stay at the current location\n            xyz[iumd][0] = xyz[iumd - 1][0];\n            xyz[iumd][1] = xyz[iumd - 1][1];\n            xyz[iumd][2] = xyz[iumd - 1][2];\n\n            // Update the target location\n            double dir = (simulator->target.bearing / 1000) / R2D;\n            neu[0] = (simulator->target.velocity * cos(dir)) * 0.1;\n            neu[1] = (simulator->target.velocity * sin(dir)) * 0.1;\n            neu[2] = simulator->target.vertical_speed * 0.1;\n\n            xyz[iumd][0] += tmat[0][0] * neu[0] + tmat[1][0] * neu[1] + tmat[2][0] * neu[2];\n            xyz[iumd][1] += tmat[0][1] * neu[0] + tmat[1][1] * neu[1] + tmat[2][1] * neu[2];\n            xyz[iumd][2] += tmat[0][2] * neu[0] + tmat[1][2] * neu[1] + tmat[2][2] * neu[2];\n        }\n\n        for (i = 0; i < MAX_CHAN; i++) {\n            if (chan[i].prn > 0) {\n                // Refresh code phase and data bit counters\n                range_t rho;\n                sv = chan[i].prn - 1;\n\n                // Current pseudorange\n                computeRange(&rho, eph[ieph][sv], &ionoutc, grx, xyz[iumd]);\n\n                chan[i].azel[0] = rho.azel[0];\n                chan[i].azel[1] = rho.azel[1];\n\n                // Update code phase and data bit counters\n                computeCodePhase(&chan[i], rho, 0.1);\n#ifndef FLOAT_CARR_PHASE\n                chan[i].carr_phasestep = (int) round(512.0 * 65536.0 * chan[i].f_carr * delt);\n#endif\n                // Path loss\n                path_loss = 20200000.0 / rho.d;\n\n                // Receiver antenna gain\n                ibs = (int) ((90.0 - rho.azel[1] * R2D) / 5.0); // covert elevation to boresight\n                ant_gain = ant_pat[ibs];\n\n                // Signal gain\n                gain[i] = (double) (path_loss * ant_gain);\n                // Pluto SDR needs more signal strength due to 12 bit DAC range.\n                // Otherwise signal dynamic range is very low.\n                if (simulator->sdr_type == SDR_PLUTOSDR) {\n                    // Will result in larger IQ values, hence higher signal amplitude.\n                    // Best value to be defined.\n                    gain[i] *= 2;\n                }\n            }\n        }\n\n        for (isamp = 0; isamp < NUM_IQ_SAMPLES; isamp++) {\n            int i_acc = 0.0f;\n            int q_acc = 0.0f;\n\n            for (i = 0; i < MAX_CHAN; i++) {\n                if (chan[i].prn > 0) {\n#ifdef FLOAT_CARR_PHASE\n                    // carr_phase 0.0 - 1.0          \n                    iTable = (int) floor(chan[i].carr_phase * 512.0);\n#else\n                    iTable = (chan[i].carr_phase >> 16) & 511; // 9-bit index\n#endif\n                    // dataBit -1 or 1\n                    // codeCA  -1 or 1\n                    ip = chan[i].dataBit * chan[i].codeCA * cosTable512[iTable] * gain[i];\n                    qp = chan[i].dataBit * chan[i].codeCA * sinTable512[iTable] * gain[i];\n\n                    // Accumulate for all visible satellites\n                    i_acc += ip;\n                    q_acc += qp;\n\n                    // Update code phase\n                    chan[i].code_phase += chan[i].f_code * delt;\n\n                    if (chan[i].code_phase >= CA_SEQ_LEN) {\n                        chan[i].code_phase -= CA_SEQ_LEN;\n\n                        chan[i].icode++;\n\n                        if (chan[i].icode >= 20) // 20 C/A codes = 1 navigation data bit\n                        {\n                            chan[i].icode = 0;\n                            chan[i].ibit++;\n\n                            if (chan[i].ibit >= 30) // 30 navigation data bits = 1 word\n                            {\n                                chan[i].ibit = 0;\n                                chan[i].iword++;\n                                /*\n                                if (chan[i].iword>=N_DWRD)\n                                        fprintf(stderr, \"\\nWARNING: Subframe word buffer overflow.\\n\");\n                                 */\n                            }\n\n                            // Set new navigation data bit\n                            chan[i].dataBit = (int) ((chan[i].dwrd[chan[i].iword]>>(29 - chan[i].ibit)) & 0x1UL)*2 - 1;\n                        }\n                    }\n\n                    // Set current code chip\n                    chan[i].codeCA = chan[i].ca[(int) chan[i].code_phase]*2 - 1;\n\n                    // Update carrier phase\n#ifdef FLOAT_CARR_PHASE\n                    chan[i].carr_phase += chan[i].f_carr * delt;\n\n                    if (chan[i].carr_phase >= 1.0)\n                        chan[i].carr_phase -= 1.0;\n                    else if (chan[i].carr_phase < 0.0)\n                        chan[i].carr_phase += 1.0;\n#else\n                    chan[i].carr_phase += chan[i].carr_phasestep;\n#endif\n                }\n            }\n\n            // Store I/Q samples into buffer\n            iq_buff[isamp * 2] = (short) i_acc;\n            iq_buff[isamp * 2 + 1] = (short) q_acc;\n        }\n\n        // Fill transfer fifo\n        for (isamp = 0; isamp < IQ_BUFFER_SIZE; isamp++) {\n            // validLength starts with 0 on aquire\n            if (simulator->sample_size == SC16) {\n                iq->data16[iq->validLength] = iq_buff[isamp];\n            } else {\n                iq->data8[iq->validLength] = iq_buff[isamp] >> 4;\n            }\n            iq->validLength += 1;\n            if (simulator->sdr_type == SDR_HACKRF) {\n                // Fill one fifo block until full\n                if (iq->validLength == HACKRF_TRANSFER_BUFFER_SIZE) {\n                    // Enqueue full fifo block\n                    fifo_enqueue(iq);\n                    // Get a new one and fill as long as we don't reach IQ_BUFFER_SIZE\n                    iq = fifo_acquire();\n                }\n                // We don't enque a partly filled fifo block but keep it for the next round\n            }\n        }\n\n        // File writer and Pluto SDR taking the entire IQ buffer at once.\n        if (simulator->sdr_type == SDR_IQFILE || simulator->sdr_type == SDR_PLUTOSDR) {\n            // Enqueue full fifo block\n            fifo_enqueue(iq);\n            // Get a new one\n            iq = fifo_acquire();\n        }\n\n        //\n        // Update navigation message and channel allocation every 30 seconds\n        //\n        igrx = (int) (grx.sec * 10.0 + 0.5);\n\n        xyz2llh(xyz[iumd], llh);\n        simulator->target.lat = llh[0] * R2D;\n        simulator->target.lon = llh[1] * R2D;\n        simulator->target.height = llh[2];\n        gui_show_target(&simulator->target);\n\n        if (igrx % 300 == 0) // Every 30 seconds\n        {\n            // Update navigation message\n            for (i = 0; i < MAX_CHAN; i++) {\n                if (chan[i].prn > 0) {\n                    generateNavMsg(grx, &chan[i], 0);\n                }\n            }\n\n            // Refresh ephemeris and subframes\n            // Quick and dirty fix. Need more elegant way.\n            for (sv = 0; sv < MAX_SAT; sv++) {\n                if (eph[ieph + 1][sv].vflg == true) {\n                    dt = subGpsTime(eph[ieph + 1][sv].toc, grx);\n                    if (dt < SECONDS_IN_HOUR) {\n                        ieph++;\n                        if (ieph >= EPHEM_ARRAY_SIZE) {\n                            ieph = 0;\n                        }\n\n                        for (i = 0; i < MAX_CHAN; i++) {\n                            // Generate new subframes if allocated\n                            if (chan[i].prn != 0)\n                                eph2sbf(eph[ieph][chan[i].prn - 1], ionoutc, alm, chan[i].sbf);\n                        }\n                    }\n                    break;\n                }\n            }\n\n            // Update channel allocation\n            allocateChannel(chan, alm, eph[ieph], ionoutc, grx, xyz[0], elvmask);\n\n            if (simulator->show_verbose) {\n                gps2date(&grx, &simulator->start);\n                gui_mvwprintw(LS_FIX, 11, 57, \"%4d/%02d/%02d,%02d:%02d:%02.0f (%d:%.0f)\",\n                        simulator->start.y, simulator->start.m, simulator->start.d, simulator->start.hh, simulator->start.mm, simulator->start.sec, grx.week, grx.sec);\n                gui_mvwprintw(LS_FIX, 5, 40, \"xyz = %11.1f, %11.1f, %11.1f\", xyz[iumd][0], xyz[iumd][1], xyz[iumd][2]);\n                gui_mvwprintw(LS_FIX, 6, 40, \"llh = %11.6f, %11.6f, %11.1f\", llh[0] * R2D, llh[1] * R2D, llh[2]);\n                start_y = 4;\n                for (i = 0; i < 33; i++) sat_simulated[i] = false;\n                for (i = 0; i < MAX_CHAN; i++) {\n                    if (chan[i].prn > 0) {\n                        gui_mvwprintw(LS_FIX, start_y++, 1, \"%02d %6.1f %5.1f %11.1f %5.1f\", chan[i].prn,\n                                chan[i].azel[0] * R2D, chan[i].azel[1] * R2D, chan[i].rho0.d, chan[i].rho0.iono_delay);\n                    }\n\n                    sat_simulated[chan[i].prn] = true;\n                }\n\n                gui_mvwprintw(LS_FIX, 3, 40, \"Nav: %02d satellites\", start_y - 4);\n            }\n        }\n        // Update receiver time\n        grx = incGpsTime(grx, 0.1);\n\n        // Update time counter\n        gui_mvwprintw(LS_FIX, 12, 40, \"Elapsed:         %5.1fs\", subGpsTime(grx, g0));\n    }\n\n    gui_status_wprintw(GREEN, \"Simulation complete\\n\");\n\nend_gps_thread:\n    free(iq_buff);\n    if (xyz)\n        free(xyz);\n    gui_status_wprintw(RED, \"Exit GPS thread\\n\");\n    simulator->gps_thread_exit = true;\n    pthread_cond_signal(&(simulator->gps_init_done));\n    pthread_exit(NULL);\n}\n"
  },
  {
    "path": "gps.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#ifndef GPS_H\n#define GPS_H\n\n/* For RKT simulation. Higher computational load, but smoother carrier phase.*/\n#define FLOAT_CARR_PHASE\n\n/* Real-time signal generation */\n#define REAL_TIME_GPS\n\n#define RINEX2_FILE_NAME \"rinex2.gz\"\n#define RINEX3_FILE_NAME \"rinex3.gz\"\n#define RINEX_FTP_URL \"ftp://igs.bkg.bund.de/IGS/\"\n#define RINEX2_SUBFOLDER \"nrt\"\n#define RINEX3_SUBFOLDER \"nrt_v3\"\n#define RINEX_FTP_FILE \"%s/%03i/%02i/%4s%03i%c.%02in.gz\"\n\n/* Maximum length of a line in a text file (RINEX, motion) */\n#define MAX_CHAR (100)\n\n/* Maximum number of satellites in RINEX file */\n#define MAX_SAT (32)\n\n/* Maximum number of channels we simulate */\n#define MAX_CHAN (12)\n\n/* Maximum number of user motion points */\n#ifndef REAL_TIME_GPS\n#define USER_MOTION_SIZE (3000) // max duration at 10Hz\n#else\n#define USER_MOTION_SIZE (864000) // for 24 hours at 10Hz\n#endif\n\n/* Number of subframes */\n#define N_SBF (5) // 5 subframes per frame\n\n/* Number of words per subframe */\n#define N_DWRD_SBF (10) // 10 word per subframe\n\n/* Number of words */\n#define N_DWRD ((N_SBF+1)*N_DWRD_SBF) // Subframe word buffer size\n\n#define N_SBF_PAGE (3+2*25) // Subframes 1 to 3 and 25 pages of subframes 4 and 5\n#define MAX_PAGE (25)\n\n/* C/A code sequence length */\n#define CA_SEQ_LEN (1023)\n\n#define SECONDS_IN_WEEK 604800.0\n#define SECONDS_IN_HALF_WEEK 302400.0\n#define SECONDS_IN_DAY 86400.0\n#define SECONDS_IN_HOUR 3600.0\n#define SECONDS_IN_MINUTE 60.0\n\n#define POW2_M5  0.03125\n#define POW2_M19 1.907348632812500e-6\n#define POW2_M29 1.862645149230957e-9\n#define POW2_M31 4.656612873077393e-10\n#define POW2_M33 1.164153218269348e-10\n#define POW2_M43 1.136868377216160e-13\n#define POW2_M55 2.775557561562891e-17\n\n#define POW2_M50 8.881784197001252e-016\n#define POW2_M30 9.313225746154785e-010\n#define POW2_M27 7.450580596923828e-009\n#define POW2_M24 5.960464477539063e-008\n\n#define POW2_M21 4.76837158203125e-007\n#define POW2_12  4096\n#define POW2_M38 3.63797880709171e-012\n#define POW2_M11 0.00048828125\n#define POW2_M23 1.19209289550781e-007\n#define POW2_M20 9.5367431640625e-007\n\n// Conventional values employed in GPS ephemeris model (ICD-GPS-200)\n#define GM_EARTH 3.986005e14\n#define OMEGA_EARTH 7.2921151467e-5\n\n#ifndef PI\n#define PI 3.1415926535898\n#endif\n\n#define WGS84_RADIUS 6378137.0\n#define WGS84_ECCENTRICITY 0.0818191908426\n\n#ifndef R2D\n#define R2D 57.2957795131 // *180/pi\n#endif\n\n#define SPEED_OF_LIGHT 2.99792458e8\n#define LAMBDA_L1 0.190293672798365\n\n/* C/A code frequency */\n#define CODE_FREQ (1.023e6)\n#define CARR_TO_CODE (1.0/1540.0)\n\n#define EPHEM_ARRAY_SIZE (13) // for daily GPS broadcast ephemers file (brdc)\n\n/* GPS parity bit-vectors\n * The last 6 bits of a 30bit GPS word are parity check bits.\n * Each parity bit is computed from the XOR of a selection of bits from the\n * 1st 24 bits of the current GPS word, and the last 2 bits of the _previous_\n * GPS word.\n * These parity bit-vectors are used to select which message bits will be used\n * for computing each of the 6 parity check bits.\n * We assume the two bits from the previous message (b29, b30) and the 24 bits\n * from the current message, are packed into a 32bit word in this order:\n * < b29, b30, b1, b2, b3, ... b23, b24, X, X, X, X, X, X > (X = don't care)\n * Example: if PBn = 0x40000080,\n * The parity check bit \"n\" would be computed from the expression (b30 XOR b23).\n */\n#define PB1 0xbb1f3480\n#define PB2 0x5d8f9a40\n#define PB3 0xaec7cd00\n#define PB4 0x5763e680\n#define PB5 0x6bb1f340\n#define PB6 0x8b7a89c0\n\n/*\n * The almanac message for any dummy SVs shall contain alternating ones and zeros\n * with valid parity. (IS-GPS-200L, p.111, 20.3.3.5.1.2)\n */\n#define EMPTY_WORD 0xaaaaaaaaUL \n\n/* Structure representing GPS time */\ntypedef struct {\n    int week; /* GPS week number (since January 1980) */\n    double sec; /* second inside the GPS \\a week */\n} gpstime_t;\n\n/* Structure repreenting UTC time */\ntypedef struct {\n    int y; /* Calendar year */\n    int m; /* Calendar month */\n    int d; /* Calendar day */\n    int hh; /* Calendar hour */\n    int mm; /* Calendar minutes */\n    double sec; /* Calendar seconds */\n} datetime_t;\n\n/* Structure representing ephemeris of a single satellite */\ntypedef struct {\n    int vflg; /* Valid Flag */\n    int sva; /* SV accuracy (URA index) */\n    int svh; /* SV health */\n    int code; /* 0 or 1 code L2 (Codes on L2 channel) */\n    int flag; /* L2 P data flag data indicates \n               * whether navigation data is being modulated onto the L2 P(Y) code.\n               */\n    double fit;\n    datetime_t t;\n    gpstime_t toc; /* Time of Clock */\n    gpstime_t toe; /* Time of Ephemeris */\n    int iodc; /* Issue of Data, Clock */\n    int iode; /* Isuse of Data, Ephemeris */\n    double deltan; /* Delta-N (radians/sec) */\n    double cuc; /* Cuc (radians) */\n    double cus; /* Cus (radians) */\n    double cic; /* Correction to inclination cos (radians) */\n    double cis; /* Correction to inclination sin (radians) */\n    double crc; /* Correction to radius cos (meters) */\n    double crs; /* Correction to radius sin (meters) */\n    double ecc; /* e Eccentricity */\n    double sqrta; /* sqrt(A) (sqrt(m)) */\n    double m0; /* Mean anamoly (radians) */\n    double omg0; /* Longitude of the ascending node (radians) */\n    double inc0; /* Inclination (radians) */\n    double aop;\n    double omgdot; /* Omega dot (radians/s) */\n    double idot; /* IDOT (radians/s) */\n    double af0; /* a_f0\tClock offset (seconds) */\n    double af1; /* a_f1\trate (sec/sec) */\n    double af2; /* a_f2\tacceleration (sec/sec^2) */\n    double tgd; /* Group delay L2 bias */\n    // Working variables follow\n    double n; /* Mean motion (Average angular velocity) */\n    double sq1e2; /* sqrt(1-e^2) */\n    double A; /* Semi-major axis */\n    double omgkdot; /* OmegaDot-OmegaEdot */\n} ephem_t;\n\ntypedef struct {\n    int enable;\n    int vflg;\n    double alpha0, alpha1, alpha2, alpha3;\n    double beta0, beta1, beta2, beta3;\n    double A0, A1;\n    int dtls, tot, wnt;\n    int dtlsf, dn, wnlsf;\n} ionoutc_t;\n\ntypedef struct {\n    gpstime_t g;\n    double range; // pseudorange\n    double rate;\n    double d; // geometric distance\n    double azel[2];\n    double iono_delay;\n} range_t;\n\n/* Structure representing a Channel */\ntypedef struct {\n    int prn; /* PRN Number */\n    int ca[CA_SEQ_LEN]; /* C/A Sequence */\n    double f_carr; /* Carrier frequency */\n    double f_code; /* Code frequency */\n#ifdef FLOAT_CARR_PHASE\n    double carr_phase;\n#else\n    unsigned int carr_phase; /* Carrier phase */\n    int carr_phasestep; /* Carrier phasestep */\n#endif\n    double code_phase; /* Code phase */\n    gpstime_t g0; /* GPS time at start */\n\tunsigned long sbf[N_SBF_PAGE][N_DWRD_SBF]; /*!< current subframe */\n\tunsigned long dwrd[N_DWRD]; /*!< Data words of sub-frame */\n\tint ipage;\n    int iword; /* initial word */\n    int ibit; /* initial bit */\n    int icode; /* initial code */\n    int dataBit; /* current data bit */\n    int codeCA; /* current C/A code */\n    double azel[2];\n    range_t rho0;\n} channel_t;\n\n/* Structure represending a single GPS monitoring station. */\ntypedef struct {\n    const char *id_v2;\n    const char *id_v3;\n    const char *name;\n} stations_t;\n\nvoid *gps_thread_ep(void *arg);\n\n#endif /* GPS_H */\n\n"
  },
  {
    "path": "gui.c",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n#include <stdio.h>\n#include <termios.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <string.h>\n#include <pthread.h>\n#include <ncurses.h>\n#include <panel.h>\n#include <form.h>\n#include \"gps-sim.h\"\n#include \"gps.h\"\n#include \"gui.h\"\n\nstatic const int info_width = 50;\nstatic const int info_height = 13;\nstatic const int help_width = 50;\nstatic const int help_height = 13;\nstatic int max_x = 0;\nstatic int max_y = 0;\n\nstatic WINDOW *window[13] = {NULL};\nstatic PANEL *panel[13] = {NULL};\n\nstatic pthread_mutex_t gui_lock; // Mutex to lock access during GUI updates\n\nstatic void gui_update() {\n    update_panels();\n    doupdate();\n}\n\nstatic void show_footer(WINDOW *win) {\n    wattron(win, COLOR_PAIR(2));\n    mvwprintw(win, max_y - STATUS_HEIGHT - 2, 10, \"TAB or F1-F3 switch displays, 'x' Exit, 'i' Info, 'h' Help\");\n    wattroff(win, COLOR_PAIR(2));\n}\n\n/* Show the window with a border and a label */\nstatic void show_window(WINDOW *win, char *label) {\n    int startx, half_width, str_leng;\n\n    half_width = max_x / 2;\n    str_leng = (int) strlen(label);\n    startx = half_width - (str_leng / 2);\n\n    box(win, 0, 0);\n    // Header separator\n    mvwaddch(win, 2, 0, ACS_LTEE);\n    mvwhline(win, 2, 1, ACS_HLINE, max_x - 2);\n    mvwaddch(win, 2, max_x - 1, ACS_RTEE);\n    // Status separator\n    mvwaddch(win, max_y - STATUS_HEIGHT - 2, 0, ACS_LTEE);\n    mvwhline(win, max_y - STATUS_HEIGHT - 2, 1, ACS_HLINE, max_x - 2);\n    mvwaddch(win, max_y - STATUS_HEIGHT - 2, max_x - 1, ACS_RTEE);\n    // Header label\n    wattron(win, COLOR_PAIR(1));\n    mvwprintw(win, 1, startx, \"%s\", label);\n    wattroff(win, COLOR_PAIR(1));\n    show_footer(win);\n    doupdate();\n}\n\n//print the header info for LS fix result display\n\nstatic void ls_show_header(void) {\n    wattron(window[LS_FIX], COLOR_PAIR(2));\n    mvwprintw(window[LS_FIX], 3, 1, \"PRN  AZ    ELEV  PRange       dIon\");\n    wattroff(window[LS_FIX], COLOR_PAIR(2));\n    wrefresh(window[TOP]);\n}\n\nstatic void show_heading(float degree) {\n    int bias;\n    int zero_y = 0; //coordinates of zero\n    int zero_x = 9;\n\n    //draw window outline\n    wborder(window[HEADING], '.', '.', '.', '.', '.', '.', '.', '.');\n\n    mvwaddch(window[HEADING], 0, 9, ACS_UARROW);\n    mvwprintw(window[HEADING], 1, 9, \"0\");\n    mvwprintw(window[HEADING], 6, 0, \"<270\");\n    mvwprintw(window[HEADING], 6, 16, \"90>\");\n    mvwprintw(window[HEADING], 11, 8, \"180\");\n    mvwaddch(window[HEADING], 12, 9, ACS_DARROW);\n    //wattron(window[HEADING],COLOR_PAIR(5)|A_BOLD);\n    mvwaddch(window[HEADING], 6, 9, ACS_DIAMOND);\n    //wattroff(window[HEADING],COLOR_PAIR(5)|A_BOLD);\n    //show window title\n    wattron(window[HEADING], COLOR_PAIR(11) | A_BOLD);\n    mvwprintw(window[HEADING], 4, 6, \"DIRECTION\");\n    wattroff(window[HEADING], COLOR_PAIR(11) | A_BOLD);\n\n    wattron(window[HEADING], COLOR_PAIR(13) | A_BOLD);\n    mvwprintw(window[HEADING], 8, 6, \"%6.1f\", degree);\n    wattroff(window[HEADING], COLOR_PAIR(13) | A_BOLD);\n\n    //calculate coordinates\n    bias = (int) (degree / 6);\n    //data is at top line,0~60\n    if ((bias >= 0) && (bias <= 9)) {\n        wattron(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n        mvwaddch(window[HEADING], 0, 9 + bias, ACS_DIAMOND);\n        wattroff(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n    }\n    //data is at right line 60~126\n    if ((bias >= 10) && (bias <= 20)) {\n        wattron(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n        mvwaddch(window[HEADING], zero_y + bias - 9, zero_x + 9, ACS_DIAMOND);\n        wattroff(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n    }\n    //data is at bottom line 132~180\n    if ((bias >= 21) && (bias <= 30)) {\n        wattron(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n        mvwaddch(window[HEADING], zero_y + 12, 18 - (bias - 20), ACS_DIAMOND);\n        wattroff(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n    }\n    //data is at bottom line 180~234\n    if ((bias >= 31) && (bias <= 39)) {\n        wattron(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n        mvwaddch(window[HEADING], zero_y + 12, 9 + (-bias + 30), ACS_DIAMOND);\n        wattroff(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n    }\n    //data is at left line 240~-300\n    if ((bias >= 40) && (bias <= 50)) {\n        wattron(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n        mvwaddch(window[HEADING], 12 + (-bias + 39), 0, ACS_DIAMOND);\n        wattroff(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n    }\n\n    //data is at left line 306~-360\n    if ((bias >= 51) && (bias <= 60)) {\n        wattron(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n        mvwaddch(window[HEADING], 0, bias - 51, ACS_DIAMOND);\n        wattroff(window[HEADING], COLOR_PAIR(12) | A_BOLD);\n    }\n    if (window[TOP] == window[KF_FIX]) {\n        wrefresh(window[HEADING]);\n    }\n}\n\nstatic void show_vertical_speed(float height) {\n    wattron(window[HEIGHT], COLOR_PAIR(11) | A_BOLD);\n    mvwprintw(window[HEIGHT], 0, 0, \"VERT SPEED\");\n    wattroff(window[HEIGHT], COLOR_PAIR(11) | A_BOLD);\n\n    wattron(window[HEIGHT], COLOR_PAIR(13) | A_BOLD);\n    mvwprintw(window[HEIGHT], 1, 0, \"%6.1f m/s\", height);\n    wattroff(window[HEIGHT], COLOR_PAIR(13) | A_BOLD);\n    if (window[TOP] == window[KF_FIX]) {\n        wrefresh(window[HEIGHT]);\n    }\n}\n\nstatic void show_speed(float speed) {\n    wattron(window[SPEED], COLOR_PAIR(11) | A_BOLD);\n    mvwprintw(window[SPEED], 0, 3, \"SPEED\");\n    wattroff(window[SPEED], COLOR_PAIR(11) | A_BOLD);\n\n    wattron(window[SPEED], COLOR_PAIR(13) | A_BOLD);\n    mvwprintw(window[SPEED], 1, 0, \"%6.1f km/h\", speed);\n    wattroff(window[SPEED], COLOR_PAIR(13) | A_BOLD);\n    if (window[TOP] == window[KF_FIX]) {\n        wrefresh(window[SPEED]);\n    }\n}\n\nstatic void show_target(target_t *target) {\n    mvwprintw(window[TARGET], 0, 4, \"Target:\");\n\n    mvwprintw(window[TARGET], 1, 0, \"Distance  %9.1f m\", target->distance);\n    mvwprintw(window[TARGET], 2, 0, \"Direction %9.1f deg\", target->bearing / 1000);\n    mvwprintw(window[TARGET], 3, 0, \"Height    %9.1f m\", target->height);\n    mvwprintw(window[TARGET], 4, 0, \"Longitude %9.6f deg\", target->lon);\n    mvwprintw(window[TARGET], 5, 0, \"Latitude  %9.6f deg\", target->lat);\n    if (window[TOP] == window[KF_FIX]) {\n        wnoutrefresh(window[TARGET]);\n    }\n}\n\nstatic void show_local(location_t *loc) {\n    mvwprintw(window[LOCATION], 0, 4, \"Location:\");\n    mvwprintw(window[LOCATION], 1, 0, \"Longitude %9.6f deg\", loc->lon);\n    mvwprintw(window[LOCATION], 2, 0, \"Latitude  %9.6f deg\", loc->lat);\n    mvwprintw(window[LOCATION], 3, 0, \"Height    %9.1f m\", loc->height);\n    if (window[TOP] == window[KF_FIX]) {\n        wnoutrefresh(window[LOCATION]);\n    }\n}\n\nstatic void eph_show_header(void) {\n    wattron(window[EPHEMERIS], COLOR_PAIR(2));\n    mvwprintw(window[EPHEMERIS], 3, 1, \"PRN  AZ    ELEV  EPH   SIM        \");\n    wattroff(window[EPHEMERIS], COLOR_PAIR(2));\n    wrefresh(window[TOP]);\n}\n\nstatic void init_windows(void) {\n    int info_x, info_y;\n\n    window[STATUS] = newwin(STATUS_HEIGHT, max_x - 2, max_y - STATUS_HEIGHT - 1, 1);\n    window[TRACK] = newwin(max_y, max_x, 0, 0);\n    window[LS_FIX] = newwin(max_y, max_x, 0, 0);\n    window[EPHEMERIS] = newwin(max_y, max_x, 0, 0);\n    window[KF_FIX] = newwin(max_y, max_x, 0, 0);\n    window[HEADING] = subwin(window[KF_FIX], HEAD_HEIGHT, HEAD_WIDTH, HEAD_Y, HEAD_X);\n    show_heading(0);\n    window[HEIGHT] = subwin(window[KF_FIX], 2, 12, HEAD_Y + 6, HEAD_X + 20);\n    show_vertical_speed(0);\n    window[SPEED] = subwin(window[KF_FIX], 2, 12, HEAD_Y + 6, HEAD_X - 12);\n    show_speed(0);\n    window[TARGET] = subwin(window[KF_FIX], 7, 26, 4, 30);\n    target_t t = {0};\n    show_target(&t);\n    window[LOCATION] = subwin(window[KF_FIX], 4, 26, 4, 2);\n    location_t l = {0};\n    show_local(&l);\n\n    /* setup info window */\n    info_x = (max_x - info_width) / 2;\n    info_y = (max_y - info_height) / 2;\n    window[INFO] = newwin(info_height, info_width, info_y, info_x);\n    box(window[INFO], 0, 0);\n    wattron(window[INFO], COLOR_PAIR(1));\n    mvwprintw(window[INFO], 1, 2, \"Multi SDR GPS Simulator\");\n    wattroff(window[INFO], COLOR_PAIR(1));\n    wattron(window[INFO], COLOR_PAIR(2));\n    mvwprintw(window[INFO], 3, 2, \"https://github.com/Mictronics/multi-sdr-gps\");\n    mvwprintw(window[INFO], 4, 2, \"(c) Mictronics 2021\");\n    mvwprintw(window[INFO], 5, 2, \"Distributed under the MIT License\");\n    mvwprintw(window[INFO], 7, 2, \"Based on work from Takuji Ebinuma (gps-sdr-sim)\");\n    mvwprintw(window[INFO], 8, 2, \"and IvanKor.\");\n    mvwprintw(window[INFO], info_height - 2, 2, \"Press any key to return.\");\n    wattroff(window[INFO], COLOR_PAIR(2));\n\n    /* setup help window */\n    info_x = (max_x - help_width) / 2;\n    info_y = (max_y - help_height) / 2;\n    window[HELP] = newwin(help_height, help_width, info_y, info_x);\n    box(window[HELP], 0, 0);\n    wattron(window[HELP], COLOR_PAIR(1));\n    mvwprintw(window[HELP], 1, 2, \"Help\");\n    wattroff(window[HELP], COLOR_PAIR(1));\n    mvwprintw(window[HELP], 2, 2, \"w   Increase altitude     i    Info\");\n    mvwprintw(window[HELP], 3, 2, \"s   Decrease altitude     h    Help\");\n    mvwprintw(window[HELP], 4, 2, \"d   Heading right         x    Exit\");\n    mvwprintw(window[HELP], 5, 2, \"a   Heading left          F1   Setup Window\");\n    mvwprintw(window[HELP], 6, 2, \"e   Increase speed        F2   Status Window\");\n    mvwprintw(window[HELP], 7, 2, \"q   Decrease speed        F3   Position Window\");\n    mvwprintw(window[HELP], 8, 2, \"t   Increase TX gain\");\n    mvwprintw(window[HELP], 9, 2, \"g   Decrease TX gain\");\n\n    /* Attach a panel to each window\n     * Order is bottom up\n     */\n    panel[TRACK] = new_panel(window[TRACK]);\n    panel[LS_FIX] = new_panel(window[LS_FIX]);\n    panel[KF_FIX] = new_panel(window[KF_FIX]);\n    panel[EPHEMERIS] = new_panel(window[EPHEMERIS]);\n    panel[INFO] = new_panel(window[INFO]);\n    panel[STATUS] = new_panel(window[STATUS]);\n    panel[HELP] = new_panel(window[HELP]);\n    hide_panel(panel[INFO]);\n    hide_panel(panel[HELP]);\n\n    /* Set up the user pointers to the next panel */\n\n    set_panel_userptr(panel[TRACK], panel[LS_FIX]);\n    set_panel_userptr(panel[LS_FIX], panel[KF_FIX]);\n    set_panel_userptr(panel[KF_FIX], panel[EPHEMERIS]);\n    set_panel_userptr(panel[EPHEMERIS], panel[TRACK]);\n\n    //Print title of each window\n    show_window(window[TRACK], \"GPS Simulator Setup\");\n    show_window(window[LS_FIX], \"GPS Simulation Status\");\n    show_window(window[EPHEMERIS], \"Test\");\n    show_window(window[KF_FIX], \"Dynamic Position\");\n\n    ls_show_header();\n    top_panel(panel[TRACK]);\n    panel[TOP] = panel[TRACK];\n\n    // Keep status window scrolling when adding lines\n    scrollok(window[STATUS], TRUE);\n\n    /* Update the stacking order.tracking_panel will be on the top*/\n    update_panels();\n    doupdate();\n}\n\nvoid gui_init(void) {\n    char ch;\n    pthread_mutex_init(&gui_lock, NULL);\n    pthread_mutex_lock(&gui_lock);\n    /* Initialize curses */\n    initscr();\n    getmaxyx(stdscr, max_y, max_x);\n    endwin();\n    /*check if the col and row meet the threshold */\n    if (max_y < ROW_THRD || max_x < COL_THRD) {\n        printf(\"Your console window size is %dx%d need 26x120\\n\", max_y, max_x);\n        printf(\"Do you still want to continue? [Y/N] \");\n        ch = getchar();\n        if ((ch != 'y') && (ch != 'Y')) {\n            exit(0);\n        }\n    }\n    /* redo the initialization */\n    initscr();\n    getmaxyx(stdscr, max_y, max_x);\n    start_color();\n    cbreak();\n    noecho();\n    curs_set(0); //no cursor\n    keypad(stdscr, TRUE);\n    timeout(100);\n    /* Initialize all the colors */\n    init_pair(1, COLOR_RED, COLOR_BLACK);\n    init_pair(2, COLOR_GREEN, COLOR_BLACK);\n    init_pair(3, COLOR_BLUE, COLOR_BLACK);\n    init_pair(4, COLOR_CYAN, COLOR_BLACK);\n    init_pair(5, COLOR_YELLOW, COLOR_BLACK);\n\n    init_pair(11, COLOR_BLUE, COLOR_BLACK);\n    init_pair(12, COLOR_RED, COLOR_BLACK);\n    init_pair(13, COLOR_RED, COLOR_WHITE);\n    init_pair(14, COLOR_BLACK, COLOR_RED);\n\n    init_windows();\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_destroy(void) {\n    pthread_mutex_unlock(&gui_lock); // Just in case\n    pthread_mutex_destroy(&gui_lock);\n    delwin(window[TRACK]);\n    delwin(window[LS_FIX]);\n    delwin(window[KF_FIX]);\n    delwin(window[INFO]);\n    delwin(window[HEADING]);\n    delwin(window[HEIGHT]);\n    delwin(window[SPEED]);\n    delwin(window[TARGET]);\n    delwin(window[LOCATION]);\n    delwin(window[EPHEMERIS]);\n    delwin(window[STATUS]);\n    delwin(window[HELP]);\n    endwin();\n}\n\nvoid gui_mvwprintw(window_panel_t w, int y, int x, const char * fmt, ...) {\n    pthread_mutex_lock(&gui_lock);\n    va_list args;\n    if (wmove(window[w], y, x) == ERR) {\n        return;\n    }\n    va_start(args, fmt);\n    vw_printw(window[w], fmt, args);\n    va_end(args);\n    // Refresh only what is printed on top panel, don't care about background\n    // updates.\n    wrefresh(window[TOP]);\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_status_wprintw(status_color_t clr, const char * fmt, ...) {\n    pthread_mutex_lock(&gui_lock);\n    va_list args;\n    va_start(args, fmt);\n    if (clr > 0) {\n        wattron(window[STATUS], COLOR_PAIR(clr));\n    }\n    vw_printw(window[STATUS], fmt, args);\n    if (clr > 0) {\n        wattroff(window[STATUS], COLOR_PAIR(clr));\n    }\n    va_end(args);\n    wrefresh(window[STATUS]);\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_colorpair(window_panel_t w, unsigned clr, attr_status_t onoff) {\n    pthread_mutex_lock(&gui_lock);\n    if (onoff == ON) {\n        wattron(window[w], COLOR_PAIR(clr));\n    } else {\n        wattroff(window[w], COLOR_PAIR(clr));\n    }\n    pthread_mutex_unlock(&gui_lock);\n}\n\nint gui_getch(void) {\n    int ch = getch();\n    /*\n    if (ch != -1) {\n        fprintf(stderr, \"%i\\n\", ch);\n    }\n     */\n    return ch;\n}\n\nvoid gui_top_panel(window_panel_t p) {\n    pthread_mutex_lock(&gui_lock);\n    top_panel(panel[p]);\n    panel[TOP] = panel[p];\n    window[TOP] = window[p];\n    // Status is alway the top most panel\n    top_panel(panel[STATUS]);\n    gui_update();\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_toggle_current_panel(void) {\n    pthread_mutex_lock(&gui_lock);\n    panel[TOP] = (PANEL *) panel_userptr(panel[TOP]);\n    top_panel(panel[TOP]);\n    window[TOP] = panel_window(panel[TOP]);\n    // Status is alway the top most panel\n    top_panel(panel[STATUS]);\n    gui_update();\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_show_panel(window_panel_t p, attr_status_t onoff) {\n    pthread_mutex_lock(&gui_lock);\n    if (onoff == ON) {\n        show_panel(panel[p]);\n    } else {\n        hide_panel(panel[p]);\n    }\n    gui_update();\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_show_speed(float speed) {\n    pthread_mutex_lock(&gui_lock);\n    show_speed(speed);\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_show_heading(float hdg) {\n    pthread_mutex_lock(&gui_lock);\n    show_heading(hdg);\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_show_vertical_speed(float vs) {\n    pthread_mutex_lock(&gui_lock);\n    show_vertical_speed(vs);\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_show_location(void *l) {\n    pthread_mutex_lock(&gui_lock);\n    show_local((location_t *) (l));\n    pthread_mutex_unlock(&gui_lock);\n}\n\nvoid gui_show_target(void *t) {\n    pthread_mutex_lock(&gui_lock);\n    show_target((target_t *) (t));\n    pthread_mutex_unlock(&gui_lock);\n}\n"
  },
  {
    "path": "gui.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#ifndef GUI_H\n#define GUI_H\n\n#define ROW_THRD 26\n#define COL_THRD 120\n#define HEAD_HEIGHT 13\n#define HEAD_WIDTH 19\n#define HEAD_Y  12\n#define HEAD_X  14\n#define STATUS_HEIGHT 10\n\n// Interactive keys\n#define UP_KEY   'w'\n#define DOWN_KEY  's'\n#define RIGHT_KEY  'd'\n#define LEFT_KEY  'a'\n#define UPSPEED_KEY  'e'\n#define DOWNSPEED_KEY 'q'\n#define GAIN_INC_KEY 't'\n#define GAIN_DEC_KEY 'g'\n\ntypedef enum {\n    TRACK = 0,\n    LS_FIX,\n    KF_FIX,\n    INFO,\n    HEADING,\n    HEIGHT,\n    SPEED,\n    TARGET,\n    LOCATION,\n    EPHEMERIS,\n    TOP,\n    STATUS,\n    HELP\n} window_panel_t;\n\ntypedef enum {\n    OFF = 0,\n    ON = 1\n} attr_status_t;\n\ntypedef enum {\n    DEFAULT = 0,\n    RED = 1,\n    GREEN = 2,\n    BLUE = 3,\n    CYAN = 4,\n    YELLOW = 5\n} status_color_t;\n\nvoid gui_init(void);\nint gui_getch(void);\nvoid gui_destroy(void);\nvoid gui_mvwprintw(window_panel_t w, int y, int x, const char * fmt, ...);\nvoid gui_status_wprintw(status_color_t clr, const char * fmt, ...);\nvoid gui_colorpair(window_panel_t w, unsigned clr, attr_status_t onoff);\nvoid gui_top_panel(window_panel_t p);\nvoid gui_toggle_current_panel(void);\nvoid gui_show_panel(window_panel_t p, attr_status_t onoff);\nvoid gui_show_speed(float speed);\nvoid gui_show_heading(float hdg);\nvoid gui_show_vertical_speed(float vs);\nvoid gui_show_location(void *l);\nvoid gui_show_target(void *t);\n\n#endif /* GUI_H */\n\n"
  },
  {
    "path": "help.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#ifndef HELP_H\n#define HELP_H\n\n#include <argp.h>\nconst char *argp_program_bug_address = \"https://github.com/Mictronics/multi-sdr-gps-sim\";\nstatic error_t parse_opt(int key, char *arg, struct argp_state *state);\n\nstatic struct argp_option options[] = {\n    {0, 0, 0, 0, \"Options:\", 1},\n    {\"nav-file\", 'e', \"filename\", 0, \"RINEX navigation file for GPS ephemeris (required)\", 1},\n    {\"use-ftp\", 'f', 0, 0, \"Pull actual RINEX navigation file and almanac from online source\", 1},\n    {\"geo-loc\", 'l', \"location\", 0, \"Latitude, Longitude, Height (static mode) e.g. 35.681298,139.766247,10.0\", 1},\n    {\"start\", 's', \"date,time\", 0, \"Scenario start time YYYY/MM/DD,hh:mm:ss (use 'now' for actual time)\", 1},\n    {\"disable-iono\", 'I', 0, 0, \"Disable ionospheric delay for spacecraft scenario\", 1},\n    {\"verbose\", 'v', 0, 0, \"Show verbose output and details about simulated channels\", 1},\n    {\"interactive\", 'i', 0, 0, \"Use interactive mode\", 1},\n    {\"amplifier\", 'a', 0, 0, \"Enable TX amplifier (default OFF)\", 1},\n    {\"gain\", 'g', \"gain\", 0, \"Set initial TX gain, HackRF: 0-47dB, Pluto: -80-0dB (default 0)\", 1},\n    {\"duration\", 'd', \"seconds\", 0, \"Duration in seconds\", 1},\n    {\"target\", 't', \"distance,bearing,height\", 0, \"Target distance [m], bearing [°] and height [m]\", 1},\n    {\"ppb\", 'p', \"ppb\", 0, \"Set oscillator error in ppb (default 0)\", 1},\n    {\"rinex3\", '3', 0, 0, \"Use RINEX v3 navigation data format\", 1},\n    {\"radio\", 'r', \"name\", 0, \"Set the SDR device type name (default none)\", 1},\n    {\"iq16\", 700, 0, 0, \"Set IQ sample size to 16 bit (default 8 bit)\", 1},\n    {\"uri\", 'U', \"uri\", 0, \"ADLAM-Pluto URI\", 1},\n    {\"network\", 'N', \"network\", 0, \"ADLAM-Pluto network IP or hostname (default pluto.local)\", 1},\n    {\"motion\", 'm', \"name\", 0, \"User motion file (dynamic mode)\", 1},\n    {\"disable-almanac\", 702, 0, 0, \"Disable transmission of almanac information\", 1},\n    {\"station\", 701, \"id\", 0, \"Use station with given ID for RINEX FTP download (4 or 9 character ID)\", 2},\n    {0, 0, 0, OPTION_DOC, \"Station is a GPS ground station around the world which provides RINEX hourly updated data. See gps.c for station details. A random station is picked if no ID is given\", 2},\n    {0, 0, 0, 0, \"SDR device types (use with --radio or -r option):\", 3},\n    {0, 0, 0, OPTION_DOC, \"   none\", 3},\n    {0, 0, 0, OPTION_DOC, \"   iqfile\", 3},\n#ifdef ENABLE_HACKRFSDR    \n    {0, 0, 0, OPTION_DOC, \"   hackrf\", 3},\n#endif\n#ifdef ENABLE_PLUTOSDR\n    {0, 0, 0, OPTION_DOC, \"   plutosdr\", 3},\n#endif    \n    { 0}\n};\n\n#endif /* HELP_H */\n\n"
  },
  {
    "path": "sdr.c",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#include \"gui.h\"\n#include \"sdr_hackrf.h\"\n#include \"sdr_iqfile.h\"\n#include \"sdr_pluto.h\"\n#include \"sdr.h\"\n\nstatic int no_init(void);\nstatic void no_close(void);\nstatic int no_run(void);\nstatic int no_set_gain(const int);\n\ntypedef struct {\n    int (*init)();\n    void (*close)();\n    int (*run)();\n    int (*set_gain)(const int);\n    const char *name;\n    sdr_type_t sdr_type;\n} sdr_handler;\n\nstatic sdr_type_t current_type = SDR_NONE;\n\nstatic sdr_handler sdr_handlers[] = {\n    { no_init, no_close, no_run, no_set_gain, \"none\", SDR_NONE},\n    { sdr_iqfile_init, sdr_iqfile_close, sdr_iqfile_run, no_set_gain, \"iqfile\", SDR_IQFILE},\n#ifdef ENABLE_HACKRFSDR\n    { sdr_hackrf_init, sdr_hackrf_close, sdr_hackrf_run, sdr_hackrf_set_gain, \"hackrf\", SDR_HACKRF},\n#endif\n\n#ifdef ENABLE_PLUTOSDR\n    { sdr_pluto_init, sdr_pluto_close, sdr_pluto_run, sdr_pluto_set_gain, \"plutosdr\", SDR_PLUTOSDR},\n#endif\n    { NULL, NULL, NULL, NULL, NULL, SDR_NONE} /* must come last */\n};\n\nstatic int no_init() {\n    gui_status_wprintw(RED, \"SDR type not recognized; supported SDR types are:\\n\");\n    for (int i = 0; sdr_handlers[i].name; ++i) {\n        gui_status_wprintw(RED, \"  %s\\n\", sdr_handlers[i].name);\n    }\n    return -1;\n}\n\nstatic void no_close() {\n}\n\nstatic int no_run() {\n    return -1;\n}\n\nstatic int no_set_gain(const int gain) {\n    NOTUSED(gain);\n    return -100;\n}\n\nstatic sdr_handler *current_handler(void) {\n    for (int i = 0; sdr_handlers[i].name; ++i) {\n        if (current_type == sdr_handlers[i].sdr_type) {\n            return &sdr_handlers[i];\n        }\n    }\n\n    return &sdr_handlers[0];\n}\n\nint sdr_init(simulator_t *simulator) {\n    for (int i = 0; sdr_handlers[i].name; ++i) {\n        if (!strcasecmp(sdr_handlers[i].name, simulator->sdr_name)) {\n            current_type = sdr_handlers[i].sdr_type;\n            simulator->sdr_type = sdr_handlers[i].sdr_type;\n        }\n    }\n\n    return current_handler()->init(simulator);\n}\n\nvoid sdr_close(void) {\n    current_handler()->close();\n}\n\nint sdr_run(void) {\n    return current_handler()->run();\n}\n\nint sdr_set_gain(const int gain) {\n    return current_handler()->set_gain(gain);\n}"
  },
  {
    "path": "sdr.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#ifndef SDR_H\n#define SDR_H\n\n#include \"gps-sim.h\"\n\n#define TX_FREQUENCY 1575420000\n#define FREQ_ONE_MHZ (1000000ull)\n// 3 MHz is generated in Pluto SDR with integer dividers being multiple of 2\n#define TX_SAMPLERATE 3000000\n#define TX_BW (TX_SAMPLERATE * 2)\n\n#define NUM_FIFO_BUFFERS 8\n// Number of samples for 0.1 second transmission\n#define NUM_IQ_SAMPLES (TX_SAMPLERATE / 10)\n// Size in number of IQ samples, one I and one Q per sample\n// Size in IQ elements, not bytes!\n#define IQ_BUFFER_SIZE (NUM_IQ_SAMPLES * 2)\n\n// HackRF transfer buffer size\n// Fixed to 4 * 8192 = 262144 bytes\n// Defined in libhackrf, hackrf.c\n#define HACKRF_TRANSFER_BUFFER_SIZE 262144\n\nint sdr_init(simulator_t *simulator);\nvoid sdr_close(void);\nint sdr_run(void);\nint sdr_set_gain(int gain);\n\n#endif /* SDR_H */\n\n"
  },
  {
    "path": "sdr_hackrf.c",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <fcntl.h> \n#include <sys/stat.h> \n#include <sys/types.h> \n/* for PRIX64 */\n#include <inttypes.h>\n#include <hackrf.h>\n#include \"gui.h\"\n#include \"fifo.h\"\n#include \"sdr.h\"\n#include \"sdr_hackrf.h\"\n\nstatic hackrf_device_list_t *list;\nstatic hackrf_device* device;\nstatic const int gui_y_offset = 4;\nstatic const int gui_x_offset = 2;\n\nint sdr_hackrf_init(simulator_t *simulator) {\n    int result = HACKRF_SUCCESS;\n    uint8_t board_id = BOARD_ID_INVALID;\n    char version[255 + 1];\n    uint16_t usb_version;\n    read_partid_serialno_t read_partid_serialno;\n    uint8_t operacakes[8];\n    double sample_rate_gps_hz;\n    uint32_t baseband_filter_bw_hackrf_hz = 0;\n    uint64_t freq_gps_hz;\n    int y = gui_y_offset;\n\n    // HackRF wants 8 bit signed samples\n    if (simulator->sample_size == SC16) {\n        gui_status_wprintw(YELLOW, \"16 bit sample size requested. Reset to 8 bit with HackRF.\\n\");\n    }\n    simulator->sample_size = SC08;\n\n    result = hackrf_init();\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_init() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    list = hackrf_device_list();\n    if (list->devicecount < 1) {\n        gui_status_wprintw(RED, \"No HackRF boards found.\\n\");\n        return -1;\n    }\n\n    if (list->devicecount > 1) {\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"Found %d HackRF devices. Using index 0.\", list->devicecount);\n    } else {\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"Found HackRF device.\");\n    }\n\n    if (list->serial_numbers[0]) {\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"Serial number: %s\", list->serial_numbers[0]);\n    }\n\n    device = NULL;\n    result = hackrf_device_list_open(list, 0, &device);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_open() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    result = hackrf_board_id_read(device, &board_id);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_board_id_read() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"Board ID Number: %d (%s)\", board_id, hackrf_board_id_name(board_id));\n\n    result = hackrf_version_string_read(device, &version[0], 255);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_version_string_read() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    result = hackrf_usb_api_version_read(device, &usb_version);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_usb_api_version_read() failed: %s (%d)\\n\",\n                hackrf_error_name(result), result);\n        return -1;\n    }\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"Firmware Version: %s (API:%x.%02x)\", version, (usb_version >> 8)&0xFF, usb_version & 0xFF);\n\n    result = hackrf_board_partid_serialno_read(device, &read_partid_serialno);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_board_partid_serialno_read() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"Part ID Number: 0x%08x 0x%08x\",\n            read_partid_serialno.part_id[0],\n            read_partid_serialno.part_id[1]);\n\n    result = hackrf_get_operacake_boards(device, &operacakes[0]);\n    if ((result != HACKRF_SUCCESS) && (result != HACKRF_ERROR_USB_API_VERSION)) {\n        gui_status_wprintw(RED, \"hackrf_get_operacake_boards() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n    if (result == HACKRF_SUCCESS) {\n        for (int j = 0; j < 8; j++) {\n            if (operacakes[j] == 0)\n                break;\n            gui_mvwprintw(TRACK, y++, gui_x_offset, \"Operacake found, address: 0x%02x\", operacakes[j]);\n        }\n    }\n\n#ifdef HACKRF_ISSUE_609_IS_FIXED\n    uint32_t cpld_crc = 0;\n    result = hackrf_cpld_checksum(device, &cpld_crc);\n    if ((result != HACKRF_SUCCESS) && (result != HACKRF_ERROR_USB_API_VERSION)) {\n        gui_status_wprintw(RED, \"hackrf_cpld_checksum() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n    if (result == HACKRF_SUCCESS) {\n        gui_mvwprintw(TRACK, y++, 60, \"CPLD checksum: 0x%08x\\n\", cpld_crc);\n    }\n#endif /* HACKRF_ISSUE_609_IS_FIXED */\n\n    sample_rate_gps_hz = TX_SAMPLERATE;\n    freq_gps_hz = TX_FREQUENCY;\n    // Change the freq and sample rate to correct the crystal clock error.\n    // sample_rate_gps_hz = (uint32_t) ((double) sample_rate_gps_hz * (10000000 - simulator->ppb) / 10000000 + 0.5);\n    freq_gps_hz = freq_gps_hz * (10000000 - simulator->ppb) / 10000000;\n\n    /* Compute default value depending on sample rate */\n    baseband_filter_bw_hackrf_hz = hackrf_compute_baseband_filter_bw(TX_BW);\n\n    if (baseband_filter_bw_hackrf_hz > BASEBAND_FILTER_BW_MAX) {\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"Baseband filter BW must be less or equal to %u Hz/%.03f MHz\",\n                BASEBAND_FILTER_BW_MAX, (float) (BASEBAND_FILTER_BW_MAX / FREQ_ONE_MHZ));\n        return -1;\n    }\n\n    if (baseband_filter_bw_hackrf_hz < BASEBAND_FILTER_BW_MIN) {\n        gui_mvwprintw(TRACK, y++, 60, \"Baseband filter BW must be greater or equal to %u Hz/%.03f MHz\",\n                BASEBAND_FILTER_BW_MIN, (float) (BASEBAND_FILTER_BW_MIN / FREQ_ONE_MHZ));\n        return -1;\n    }\n\n    // Disable antenna bias tee.\n    result = hackrf_set_antenna_enable(device, 0);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_set_antenna_enable() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"Sample rate (%.0lf Hz/%.03f MHz)\", sample_rate_gps_hz, ((float) sample_rate_gps_hz / (float) FREQ_ONE_MHZ));\n    result = hackrf_set_sample_rate(device, sample_rate_gps_hz);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_sample_rate_set() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"Baseband filter bandwidth (%d Hz/%.03f MHz)\",\n            baseband_filter_bw_hackrf_hz, ((float) baseband_filter_bw_hackrf_hz / (float) FREQ_ONE_MHZ));\n    result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hackrf_hz);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\\n\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"Freq (%\" PRIu64 \" Hz/%.03f MHz)\", freq_gps_hz, ((double) freq_gps_hz / (double) FREQ_ONE_MHZ));\n    result = hackrf_set_freq(device, freq_gps_hz);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_set_freq() failed: %s (%d)\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    if (simulator->enable_tx_amp) {\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"Amplifier enabled\");\n        result = hackrf_set_amp_enable(device, 1);\n    } else {\n        result = hackrf_set_amp_enable(device, 0);\n    }\n\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_set_amp_enable() failed: %s (%d)\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    if (simulator->tx_gain < TX_IF_GAIN_MIN) {\n        simulator->tx_gain = TX_IF_GAIN_MIN;\n    } else if (simulator->tx_gain > TX_IF_GAIN_MAX) {\n        simulator->tx_gain = TX_IF_GAIN_MAX;\n    }\n\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"TX IF gain: %idB\", simulator->tx_gain);\n    result = hackrf_set_txvga_gain(device, simulator->tx_gain);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_set_txvga_gain() failed: %s (%d)\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    result = hackrf_set_hw_sync_mode(device, 0);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_set_hw_sync_mode() failed: %s (%d)\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    if (!fifo_create(NUM_FIFO_BUFFERS, HACKRF_TRANSFER_BUFFER_SIZE, sizeof (signed char))) {\n        gui_status_wprintw(RED, \"Error creating TX fifo!\");\n        return -1;\n    }\n\n    return 0;\n}\n\nvoid sdr_hackrf_close(void) {\n    fifo_halt();\n    fifo_destroy();\n    if (device != NULL) {\n        hackrf_stop_tx(device);\n        hackrf_set_amp_enable(device, 0);\n        hackrf_set_txvga_gain(device, 0);\n        hackrf_close(device);\n    }\n    hackrf_device_list_free(list);\n    hackrf_exit();\n}\n\nstatic int sdr_tx_callback(hackrf_transfer *transfer) {\n    // Get a fifo block\n    struct iq_buf *iq = fifo_dequeue();\n    if (iq != NULL && iq->data8 != NULL) {\n        // Fifo has transfer block size\n        memcpy(transfer->buffer, iq->data8, transfer->valid_length);\n        // Release and free up used block\n        fifo_release(iq);\n        return 0;\n    }\n\n    return -1;\n}\n\nint sdr_hackrf_run(void) {\n    if (device == NULL) {\n        gui_status_wprintw(RED, \"HackRF device is NULL\\n\");\n        return -1;\n    }\n\n    fifo_wait_full();\n\n    int result = hackrf_start_tx(device, sdr_tx_callback, NULL);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_start_tx() failed: %s (%d)\", hackrf_error_name(result), result);\n        return -1;\n    }\n\n    return 0;\n}\n\nint sdr_hackrf_set_gain(const int gain) {\n    int g = gain;\n    if (g < TX_IF_GAIN_MIN) {\n        g = TX_IF_GAIN_MIN;\n    } else if (g > TX_IF_GAIN_MAX) {\n        g = TX_IF_GAIN_MAX;\n    }\n\n    int result = hackrf_set_txvga_gain(device, g);\n    if (result != HACKRF_SUCCESS) {\n        gui_status_wprintw(RED, \"hackrf_set_txvga_gain() failed: %s (%d)\", hackrf_error_name(result), result);\n    }\n\n    return g;\n}"
  },
  {
    "path": "sdr_hackrf.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#ifndef SDR_HACKRF_H\n#define SDR_HACKRF_H\n\n#include \"gps-sim.h\"\n\n#define TX_VGA1   0\n#define TX_IF_GAIN_MIN 0\n#define TX_IF_GAIN_MAX 47\n#define BASEBAND_FILTER_BW_MIN (1750000)  /* 1.75 MHz min value */\n#define BASEBAND_FILTER_BW_MAX (28000000) /* 28 MHz max value */\n\nint sdr_hackrf_init(simulator_t *simulator);\nvoid sdr_hackrf_close(void);\nint sdr_hackrf_run(void);\nint sdr_hackrf_set_gain(const int gain);\n\n#endif /* SDR_HACKRF_H */\n\n"
  },
  {
    "path": "sdr_iqfile.c",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#include \"gui.h\"\n#include \"sdr.h\"\n#include \"sdr_iqfile.h\"\n#include \"fifo.h\"\n\nstatic atomic_bool iqfile_thread_exit = false;\nstatic pthread_t iqfile_thread;\nstatic int sample_size = SC08;\n\nstatic void *iqfile_thread_ep(void *arg) {\n    (void) arg; // Not used\n    FILE *fp = fopen(\"iqdata.bin\", \"wb\");\n\n    if (fp == NULL) {\n        gui_status_wprintw(RED, \"Error opening IQ data file.\\n\");\n        pthread_exit(NULL);\n    }\n\n    /* On a multi-core CPU we run the main thread and reader thread on different cores.\n     * Try sticking the main thread to core 3\n     */\n    thread_to_core(3);\n    set_thread_name(\"iqfile-thread\");\n\n    while (!iqfile_thread_exit) {\n        // Get a fifo block\n        struct iq_buf *iq = fifo_dequeue();\n        if (iq != NULL) {\n            if (sample_size == sizeof (signed short)) {\n                fwrite(iq->data16, sizeof (signed short), iq->validLength, fp);\n            } else {\n                fwrite(iq->data8, sizeof (signed char), iq->validLength, fp);\n            }\n            // Release and free up used block\n            fifo_release(iq);\n            if (ferror(fp)) {\n                gui_status_wprintw(RED, \"Error writing IQ data file.\\n\");\n            }\n        }\n    }\n    fclose(fp);\n    pthread_exit(NULL);\n}\n\nint sdr_iqfile_init(simulator_t *simulator) {\n    sample_size = simulator->sample_size;\n    if (!fifo_create(NUM_FIFO_BUFFERS, IQ_BUFFER_SIZE, sample_size)) {\n        gui_status_wprintw(RED, \"Error creating IQ file fifo!\");\n        return -1;\n    }\n    return 0;\n}\n\nvoid sdr_iqfile_close(void) {\n    iqfile_thread_exit = true;\n    fifo_halt();\n    fifo_destroy();\n    pthread_join(iqfile_thread, NULL);\n}\n\nint sdr_iqfile_run(void) {\n    fifo_wait_full();\n    pthread_create(&iqfile_thread, NULL, iqfile_thread_ep, NULL);\n    return 0;\n}"
  },
  {
    "path": "sdr_iqfile.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#ifndef SDR_IQFILE_H\n#define SDR_IQFILE_H\n\nint sdr_iqfile_init(simulator_t *simulator);\nvoid sdr_iqfile_close(void);\nint sdr_iqfile_run(void);\n\n#endif /* SDR_IQFILE_H */\n\n"
  },
  {
    "path": "sdr_pluto.c",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n#include <time.h>\n#include <pthread.h>\n#include <errno.h>\n#include <signal.h>\n#include <sched.h>\n#include <unistd.h>\n/* for PRIX64 */\n#include <inttypes.h>\n#include <iio.h>\n#include <ad9361.h>\n#include \"fifo.h\"\n#include \"gui.h\"\n#include \"sdr.h\"\n#include \"sdr_pluto.h\"\n\n#include <sys/time.h>\n\nstatic atomic_bool pluto_tx_thread_exit = false;\nstatic struct iio_context *ctx = NULL;\nstatic struct iio_device *tx = NULL;\nstatic struct iio_device *phydev = NULL;\nstatic struct iio_channel *tx0_i = NULL;\nstatic struct iio_channel *tx0_q = NULL;\nstatic struct iio_buffer *tx_buffer = NULL;\nstatic pthread_t pluto_tx_thread;\nstatic const int gui_y_offset = 4;\nstatic const int gui_x_offset = 2;\n\nstatic void *pluto_tx_thread_ep(void *arg) {\n    (void) arg; // Not used\n\n    // Try sticking this thread to core 2\n    thread_to_core(2);\n    set_thread_name(\"plutosdr-thread\");\n\n    int32_t ntx = 0;\n    char *ptx_buffer = (char *) iio_buffer_start(tx_buffer);\n\n    while (!pluto_tx_thread_exit) {\n        // Get a fifo block\n        struct iq_buf *iq = fifo_dequeue();\n        if (iq != NULL && iq->data16 != NULL) {\n            // Fifo has transfer block size\n            memcpy(ptx_buffer, iq->data16, iq->validLength * sizeof (signed short));\n            // Schedule TX buffer, iio_buffer_push will block if there is no room to push to.\n            ntx = iio_buffer_push(tx_buffer);\n            if (ntx < 0) {\n                gui_status_wprintw(RED, \"Error pushing TX buffer: %d\\n\", (int) ntx);\n                break;\n            }\n            // Release and free up used block\n            fifo_release(iq);\n        } else {\n            break;\n        }\n    }\n\n    if (ctx) {\n        iio_channel_attr_write_bool(\n                iio_device_find_channel(iio_context_find_device(ctx, \"ad9361-phy\"), \"altvoltage1\", true)\n                , \"powerdown\", true); // Turn OFF TX LO\n    }\n\n    if (tx_buffer) {\n        iio_buffer_destroy(tx_buffer);\n    }\n    if (tx0_i) {\n        iio_channel_disable(tx0_i);\n    }\n    if (tx0_q) {\n        iio_channel_disable(tx0_q);\n    }\n    if (ctx) {\n        iio_context_destroy(ctx);\n    }\n\n    pthread_exit(NULL);\n}\n\nint sdr_pluto_init(simulator_t *simulator) {\n    char buf[1024];\n    struct iio_scan_context *scan_ctx;\n    struct iio_context_info **info;\n    int ret;\n    int y = gui_y_offset;\n    unsigned int irates[6];\n    long long lo_hz = 0;\n    unsigned long xo_correction = 0;\n\n    // ADLAM-Pluto wants 16 bit signed samples\n    if (simulator->sample_size == SC08) {\n        gui_status_wprintw(YELLOW, \"8 bit sample size requested. Reset to 16 bit with ADLAM-Pluto.\\n\");\n    }\n    simulator->sample_size = SC16;\n\n    scan_ctx = iio_create_scan_context(NULL, 0);\n    if (!scan_ctx) {\n        gui_status_wprintw(RED, \"Unable to create IIO scan context.\\n\");\n    } else {\n\n        ret = iio_scan_context_get_info_list(scan_ctx, &info);\n        if (ret < 0) {\n            iio_strerror(errno, buf, sizeof (buf));\n            gui_status_wprintw(RED, \"Scanning for IIO contexts failed: %s\\n\", buf);\n        }\n\n        if (ret == 0) {\n            gui_status_wprintw(RED, \"No IIO context found.\\n\");\n        } else {\n            gui_mvwprintw(TRACK, y++, gui_x_offset, \"IIO contexts:\");\n            for (int i = 0; i < ret; i++) {\n                gui_mvwprintw(TRACK, y++, gui_x_offset, \"%u: %s\",\n                        i, iio_context_info_get_description(info[i]));\n                gui_mvwprintw(TRACK, y++, gui_x_offset, \"   %s\",\n                        iio_context_info_get_uri(info[i]));\n            }\n        }\n\n        iio_context_info_list_free(info);\n        iio_scan_context_destroy(scan_ctx);\n    }\n\n    // Create IIO context to access ADALM-Pluto\n    if (simulator->pluto_hostname != NULL) {\n        ctx = iio_create_network_context(simulator->pluto_hostname);\n    } else if (simulator->pluto_uri != NULL) {\n        ctx = iio_create_context_from_uri(simulator->pluto_uri);\n    } else {\n        ctx = iio_create_default_context();\n        if (ctx == NULL) {\n            ctx = iio_create_network_context(\"pluto.local\");\n        }\n    }\n\n    if (ctx == NULL) {\n        iio_strerror(errno, buf, sizeof (buf));\n        gui_status_wprintw(RED, \"Failed creating IIO context: %s\\n\", buf);\n        return -1;\n    }\n\n    int device_count = iio_context_get_devices_count(ctx);\n    if (!device_count) {\n        gui_status_wprintw(RED, \"No supported PLUTOSDR devices found.\\n\", buf);\n        return -1;\n    }\n\n    tx = iio_context_find_device(ctx, \"cf-ad9361-dds-core-lpc\");\n    if (tx == NULL) {\n        iio_strerror(errno, buf, sizeof (buf));\n        gui_status_wprintw(RED, \"Error opening PLUTOSDR TX device: %s\\n\", buf);\n        return -1;\n    }\n\n    // Additional IQ kernel buffers, default is 4\n    iio_device_set_kernel_buffers_count(tx, 8);\n\n    // Limit user gain to Pluto constrains\n    if (simulator->tx_gain > PLUTO_TX_GAIN_MAX) simulator->tx_gain = PLUTO_TX_GAIN_MAX;\n    if (simulator->tx_gain < PLUTO_TX_GAIN_MIN) simulator->tx_gain = PLUTO_TX_GAIN_MIN;\n    // Change the freq and sample rate to correct the crystal clock error.\n    uint64_t freq_gps_hz = TX_FREQUENCY;\n    freq_gps_hz = freq_gps_hz * (10000000 - simulator->ppb) / 10000000;\n\n    phydev = iio_context_find_device(ctx, \"ad9361-phy\");\n    struct iio_channel* phy_chn = iio_device_find_channel(phydev, \"voltage0\", true);\n    iio_channel_attr_write(phy_chn, \"rf_port_select\", \"A\");\n    iio_channel_attr_write_longlong(phy_chn, \"rf_bandwidth\", TX_BW);\n    iio_channel_attr_write_longlong(phy_chn, \"sampling_frequency\", TX_SAMPLERATE);\n    iio_channel_attr_write_double(phy_chn, \"hardwaregain\", simulator->tx_gain);\n\n    iio_channel_attr_write_bool(\n            iio_device_find_channel(phydev, \"altvoltage0\", true)\n            , \"powerdown\", true); // Turn OFF RX LO\n\n    iio_channel_attr_write_longlong(\n            iio_device_find_channel(phydev, \"altvoltage1\", true)\n            , \"frequency\", freq_gps_hz); // Set TX LO frequency\n\n    tx0_i = iio_device_find_channel(tx, \"voltage0\", true);\n    if (!tx0_i)\n        tx0_i = iio_device_find_channel(tx, \"altvoltage0\", true);\n\n    tx0_q = iio_device_find_channel(tx, \"voltage1\", true);\n    if (!tx0_q)\n        tx0_q = iio_device_find_channel(tx, \"altvoltage1\", true);\n\n    iio_channel_enable(tx0_i);\n    iio_channel_enable(tx0_q);\n\n    ad9361_set_bb_rate(iio_context_find_device(ctx, \"ad9361-phy\"), TX_SAMPLERATE);\n\n    // Read back TX path oscillator chain settings\n    ret = iio_device_attr_read(phydev, \"tx_path_rates\", buf, sizeof (buf));\n    if (ret > 0) {\n        sscanf(buf, \"BBPLL:%u DAC:%u T2:%u T1:%u TF:%u TXSAMP:%u\",\n                &irates[0], &irates[1], &irates[2], &irates[3], &irates[4], &irates[5]);\n    }\n\n    // Read external reference oscillator calibration value\n    ret = iio_device_attr_read(phydev, \"xo_correction\", buf, sizeof (buf));\n    if (ret > 0) {\n        sscanf(buf, \"%lu\", &xo_correction);\n    }\n\n    // Read back real TX frequency\n    ret = iio_channel_attr_read_longlong(iio_device_find_channel(phydev, \"altvoltage1\", true), \"frequency\", &lo_hz);\n    if (ret == 0) {\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"Freq (%llu Hz/%.03f MHz)\", lo_hz, ((double) lo_hz / (double) FREQ_ONE_MHZ));\n    }\n\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"Baseband filter bandwidth (%d Hz/%.03f MHz)\", TX_BW, ((float) TX_BW / (float) FREQ_ONE_MHZ));\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"Sample rate (%u Hz/%.03f MHz)\", irates[5], ((float) irates[5] / (float) FREQ_ONE_MHZ));\n    gui_mvwprintw(TRACK, y++, gui_x_offset, \"TX gain: %idB\", simulator->tx_gain);\n\n    if (simulator->show_verbose) {\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"XO Correction: %lu Hz\", xo_correction);\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"TX path rates\");\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"   BBPLL: %4.6f\", irates[0] / 1e6);\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"   DAC: %4.6f\", irates[1] / 1e6);\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"   T1: %4.6f\", irates[3] / 1e6);\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"   T2: %4.6f\", irates[2] / 1e6);\n        gui_mvwprintw(TRACK, y++, gui_x_offset, \"   TF: %4.6f\", irates[4] / 1e6);\n    }\n\n    tx_buffer = iio_device_create_buffer(tx, NUM_IQ_SAMPLES, false);\n    if (!tx_buffer) {\n        gui_status_wprintw(RED, \"Could not create TX buffer.\\n\");\n        return -1;\n    }\n    iio_buffer_set_blocking_mode(tx_buffer, true);\n\n    if (!fifo_create(NUM_FIFO_BUFFERS, IQ_BUFFER_SIZE, SC16)) {\n        gui_status_wprintw(RED, \"Error creating IQ file fifo!\\n\");\n        return -1;\n    }\n\n    return 0;\n}\n\nvoid sdr_pluto_close(void) {\n    pluto_tx_thread_exit = true;\n    fifo_halt();\n    fifo_destroy();\n    pthread_join(pluto_tx_thread, NULL);\n}\n\nint sdr_pluto_run(void) {\n    iio_channel_attr_write_bool(\n            iio_device_find_channel(iio_context_find_device(ctx, \"ad9361-phy\"), \"altvoltage1\", true)\n            , \"powerdown\", false); // Turn ON TX LO\n\n    fifo_wait_full();\n    pthread_create(&pluto_tx_thread, NULL, pluto_tx_thread_ep, NULL);\n    return 0;\n}\n\nint sdr_pluto_set_gain(const int gain) {\n    char buf[1024];\n    double g = gain;\n    int ret;\n\n    if (g > PLUTO_TX_GAIN_MAX) g = PLUTO_TX_GAIN_MAX;\n    if (g < PLUTO_TX_GAIN_MIN) g = PLUTO_TX_GAIN_MIN;\n\n    struct iio_channel* phy_chn = iio_device_find_channel(phydev, \"voltage0\", true);\n    iio_channel_attr_write_double(phy_chn, \"hardwaregain\", g);\n\n    // Read back TX gain value\n    ret = iio_channel_attr_read(phy_chn, \"hardwaregain\", buf, sizeof (buf));\n    if (ret > 0) {\n        sscanf(buf, \"%lf\", &g);\n    }\n\n    return (int) (g);\n}"
  },
  {
    "path": "sdr_pluto.h",
    "content": "/**\n * multi-sdr-gps-sim generates a IQ data stream on-the-fly to simulate a\n * GPS L1 baseband signal using a SDR platform like HackRF or ADLAM-Pluto.\n *\n * This file is part of the Github project at\n * https://github.com/mictronics/multi-sdr-gps-sim.git\n *\n * Copyright © 2021 Mictronics\n * Distributed under the MIT License.\n *\n */\n\n/*\n * TX path oscillator chain\n * Dividers with multiple of 2 and resulting sample rate.\n * BBPLL         DAC          T2           T1          TF          TXSAMP [Hz]\n * 1024000000     32000000     16000000     8000000     4000000    1000000\n *  768000000     48000000     24000000    12000000     6000000    1500000\n * 1024000000     64000000     32000000    16000000     8000000    2000000\n * 1280000000     80000000     40000000    20000000    10000000    2500000\n *  768000000     96000000     48000000    24000000    12000000    3000000\n *  896000000    112000000     56000000    28000000    14000000    3500000\n * 1024000000    128000000     64000000    32000000    16000000    4000000\n * 1152000000    144000000     72000000    36000000    18000000    4500000\n * 1280000000    160000000     80000000    40000000    20000000    5000000\n * 1408000000    176000000     88000000    44000000    22000000    5500000\n *  768000000    192000000     96000000    48000000    24000000    6000000\n *  832000000    208000000    104000000    52000000    26000000    6500000\n *  896000000    224000000    112000000    56000000    28000000    7000000\n *  960000000    240000000    120000000    60000000    30000000    7500000\n * 1024000000    256000000    128000000    64000000    32000000    8000000\n * etc. \n * Any sample rate being a multiple of 250kHz can be generated with integer dividers.\n */\n\n#ifndef SDR_PLUTO_H\n#define SDR_PLUTO_H\n\n#define PLUTO_TX_GAIN_MIN -80\n#define PLUTO_TX_GAIN_MAX 0\n\nint sdr_pluto_init(simulator_t *simulator);\nvoid sdr_pluto_close(void);\nint sdr_pluto_run(void);\nint sdr_pluto_set_gain(const int gain);\n\n#endif /* SDR_PLUTO_H */\n\n"
  }
]