From 4554c8a451b05236e7b53c6635010f9a658f8d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Thu, 9 Sep 2021 16:09:19 +0300 Subject: [PATCH 001/123] Imagery: move signature files to a / type directory structure (a.k.a. _misc) Full path to signature file now is: location/mapset/signatures/// This new structure will allow to store arbitrary number of files for each signature. None of existing signature types utilizes the new functionality. --- include/grass/defs/imagery.h | 4 +- lib/imagery/find.c | 41 ++- lib/imagery/manage_signatures.c | 72 ++-- lib/imagery/sigfile.c | 23 +- lib/imagery/sigsetfile.c | 14 +- lib/imagery/testsuite/test_imagery_find.py | 21 +- lib/imagery/testsuite/test_imagery_sigfile.py | 14 +- .../test_imagery_signature_management.py | 317 +++++++++++------- .../testsuite/test_imagery_sigsetfile.py | 14 +- 9 files changed, 303 insertions(+), 217 deletions(-) diff --git a/include/grass/defs/imagery.h b/include/grass/defs/imagery.h index e893772ddc7..6b03761ed1e 100644 --- a/include/grass/defs/imagery.h +++ b/include/grass/defs/imagery.h @@ -148,8 +148,8 @@ int I_apply_colormap(unsigned char *, unsigned char *, unsigned, unsigned char int I_rasterize(double *, int, unsigned char, struct Cell_head *, unsigned char *); /* manage_signatures.c */ -void I__get_signatures_element(char *, I_SIGFILE_TYPE); -void I__make_signatures_element(I_SIGFILE_TYPE); +void I_get_signatures_dir(char *, I_SIGFILE_TYPE); +void I_make_signatures_dir(I_SIGFILE_TYPE); int I_signatures_remove(I_SIGFILE_TYPE, const char *); int I_signatures_copy(I_SIGFILE_TYPE, const char *, const char *, const char *); int I_signatures_rename(I_SIGFILE_TYPE, const char *, const char *); diff --git a/lib/imagery/find.c b/lib/imagery/find.c index 2ae88393289..badada86339 100644 --- a/lib/imagery/find.c +++ b/lib/imagery/find.c @@ -67,7 +67,8 @@ int I_find_group_file(const char *group, const char *file) * \param file * \return int 1 if file was found, 0 otherwise */ -int I_find_group_file2(const char *group, const char *mapset, const char *file) +int I_find_group_file2(const char *group, const char *mapset, + const char *file) { if (!I_find_group2(group, mapset)) return 0; @@ -107,7 +108,8 @@ int I_find_subgroup(const char *group, const char *subgroup) * \param mapset * \return int 1 if subrgoup was found, 0 otherwise */ -int I_find_subgroup2(const char *group, const char *subgroup, const char *mapset) +int I_find_subgroup2(const char *group, const char *subgroup, + const char *mapset) { char element[GNAME_MAX]; @@ -142,7 +144,8 @@ int I_find_subgroup_file(const char *group, const char *subgroup, if (file == NULL || *file == 0) return 0; - sprintf(element, "subgroup%c%s%c%s", HOST_DIRSEP, subgroup, HOST_DIRSEP, file); + sprintf(element, "subgroup%c%s%c%s", HOST_DIRSEP, subgroup, HOST_DIRSEP, + file); G_debug(5, "I_find_subgroup_file() element: %s", element); return G_find_file2_misc("group", element, group, G_mapset()) != NULL; @@ -158,7 +161,7 @@ int I_find_subgroup_file(const char *group, const char *subgroup, * \return int 1 if file was found, 0 otherwise */ int I_find_subgroup_file2(const char *group, const char *subgroup, - const char *mapset, const char *file) + const char *mapset, const char *file) { char element[GNAME_MAX * 2]; @@ -169,7 +172,8 @@ int I_find_subgroup_file2(const char *group, const char *subgroup, if (file == NULL || *file == 0) return 0; - sprintf(element, "subgroup%c%s%c%s", HOST_DIRSEP, subgroup, HOST_DIRSEP, file); + sprintf(element, "subgroup%c%s%c%s", HOST_DIRSEP, subgroup, HOST_DIRSEP, + file); G_debug(5, "I_find_subgroup_file2() element: %s", element); return G_find_file2_misc("group", element, group, mapset) != NULL; @@ -198,14 +202,18 @@ int I_find_subgroup_file2(const char *group, const char *subgroup, * \param mapset set NULL to search in all mapsets * \return mapset or NULL */ -const char *I_find_signature(I_SIGFILE_TYPE type, char *name, const char *mapset) { - char selem[GNAME_MAX]; /* 'signatures/type\0' */ +const char *I_find_signature(I_SIGFILE_TYPE type, char *name, + const char *mapset) +{ + char sdir[GNAME_MAX]; /* 'signatures/type\0' */ - G_debug(1, "I_find_signature(): type=%d name=%s mapset=%s", type, name, mapset); + G_debug(1, "I_find_signature(): type=%d name=%s mapset=%s", type, name, + mapset); - I__get_signatures_element(selem, type); + I_get_signatures_dir(sdir, type); - return G_find_file(selem, name, mapset); + /* We do not search for a specific file as file name is up to signature type */ + return G_find_file(sdir, name, mapset); } /*! @@ -229,12 +237,15 @@ const char *I_find_signature(I_SIGFILE_TYPE type, char *name, const char *mapset * \param mapset set NULL to search in all mapsets * \return mapset or NULL */ -const char *I_find_signature2(I_SIGFILE_TYPE type, const char *name, const char *mapset) { - char selem[GNAME_MAX]; /* 'signatures/type\0' */ +const char *I_find_signature2(I_SIGFILE_TYPE type, const char *name, + const char *mapset) +{ + char sdir[GNAME_MAX]; /* 'signatures/type\0' */ - G_debug(1, "I_find_signature2(): type=%d name=%s mapset=%s", type, name, mapset); + G_debug(1, "I_find_signature2(): type=%d name=%s mapset=%s", type, name, + mapset); - I__get_signatures_element(selem, type); + I_get_signatures_dir(sdir, type); - return G_find_file2(selem, name, mapset); + return G_find_file2(sdir, name, mapset); } diff --git a/lib/imagery/manage_signatures.c b/lib/imagery/manage_signatures.c index aa22d49ceb7..c9dd280a716 100644 --- a/lib/imagery/manage_signatures.c +++ b/lib/imagery/manage_signatures.c @@ -19,18 +19,20 @@ #include /*! - \brief Get signature element (internal use only) + \brief Get signature directory - \param element [GNAME_MAX] allocated string buffer - \param type I_SIGFILE_TYPE -*/ -void I__get_signatures_element(char *element, I_SIGFILE_TYPE type) + The directory will be in a form "signatures/". + + \param dir [GNAME_MAX] allocated string buffer + \param type I_SIGFILE_TYPE + */ +void I_get_signatures_dir(char *dir, I_SIGFILE_TYPE type) { if (type == I_SIGFILE_TYPE_SIG) { - sprintf(element, "signatures%csig", HOST_DIRSEP); + sprintf(dir, "signatures%csig", HOST_DIRSEP); } else if (type == I_SIGFILE_TYPE_SIGSET) { - sprintf(element, "signatures%csigset", HOST_DIRSEP); + sprintf(dir, "signatures%csigset", HOST_DIRSEP); } else { G_fatal_error("Programming error: unknown signature file type"); @@ -38,16 +40,20 @@ void I__get_signatures_element(char *element, I_SIGFILE_TYPE type) } /*! - \brief Make signature element (internal use only) + \brief Make signature dir + + Creates directories for storage of signature files of specified type. + E.g. "//signatures//" - \param type I_SIGFILE_TYPE -*/ -void I__make_signatures_element(I_SIGFILE_TYPE type) + \param type I_SIGFILE_TYPE + */ +void I_make_signatures_dir(I_SIGFILE_TYPE type) { - char element[GNAME_MAX]; + char dir[GNAME_MAX]; + G_make_mapset_object_group("signatures"); - I__get_signatures_element(element, type); - G_make_mapset_object_group(element); + I_get_signatures_dir(dir, type); + G_make_mapset_object_group(dir); } static int list_by_type(I_SIGFILE_TYPE, const char *, int, char ***); @@ -66,7 +72,7 @@ static int list_by_type(I_SIGFILE_TYPE, const char *, int, char ***); int I_signatures_remove(I_SIGFILE_TYPE type, const char *name) { char xname[GNAME_MAX], xmapset[GMAPSET_MAX]; - char element[GNAME_MAX]; + char dir[GNAME_MAX]; int ret = 0; G_debug(1, "I_signatures_remove(%d, %s);", type, name); @@ -79,8 +85,8 @@ int I_signatures_remove(I_SIGFILE_TYPE type, const char *name) return 1; } if (I_find_signature2(type, name, G_mapset())) { - I__get_signatures_element(element, type); - if (G_remove(element, name) == 1) { + I_get_signatures_dir(dir, type); + if (G_remove(dir, name) == 1) { G_verbose_message(_("%s removed"), name); return 0; } @@ -109,7 +115,7 @@ int I_signatures_copy(I_SIGFILE_TYPE type, const char *old_name, { char sname[GNAME_MAX], tname[GNAME_MAX], tmapset[GMAPSET_MAX], xmapset[GMAPSET_MAX]; - char element[GNAME_MAX]; + char dir[GNAME_MAX]; const char *smapset; char old_path[GPATH_MAX], new_path[GPATH_MAX]; @@ -134,13 +140,15 @@ int I_signatures_copy(I_SIGFILE_TYPE type, const char *old_name, } G_unqualified_name(old_name, NULL, sname, xmapset); - I__make_signatures_element(type); + I_make_signatures_dir(type); - I__get_signatures_element(element, type); - G_file_name(old_path, element, sname, smapset); - G_file_name(new_path, element, tname, G_mapset()); + I_get_signatures_dir(dir, type); + /* Note – we need whole directory not just an element in it thus + G_file_name and not G_file_name_misc */ + G_file_name(old_path, dir, sname, smapset); + G_file_name(new_path, dir, tname, G_mapset()); - if (G_copy_file(old_path, new_path) != 1) { + if (G_recursive_copy(old_path, new_path) != 0) { G_warning(_("Unable to copy <%s> to current mapset as <%s>"), G_fully_qualified_name(old_name, smapset), tname); return 1; @@ -164,7 +172,7 @@ int I_signatures_rename(I_SIGFILE_TYPE type, const char *old_name, const char *new_name) { char sname[GNAME_MAX], tname[GNAME_MAX], tmapset[GMAPSET_MAX]; - char element[GNAME_MAX]; + char dir[GNAME_MAX]; const char *smapset; char old_path[GPATH_MAX], new_path[GPATH_MAX]; @@ -196,9 +204,11 @@ int I_signatures_rename(I_SIGFILE_TYPE type, const char *old_name, return 1; } - I__get_signatures_element(element, type); - G_file_name(old_path, element, sname, tmapset); - G_file_name(new_path, element, tname, tmapset); + I_get_signatures_dir(dir, type); + /* Note – we need whole directory not just an element in it thus + G_file_name and not G_file_name_misc */ + G_file_name(old_path, dir, sname, tmapset); + G_file_name(new_path, dir, tname, tmapset); if (G_rename_file(old_path, new_path) != 0) { G_warning(_("Unable to rename <%s> to <%s>"), old_name, new_name); @@ -245,6 +255,7 @@ int I_signatures_list_by_type(I_SIGFILE_TYPE type, const char *mapset, * \brief Free memory allocated by I_signatures_list_by_type * * Calls G_free for all list items returned by I_signatures_list_by_type() + * Sets pointer to NULL to prevent accidental use after free. * * \param int Return value of I_signatures_list_by_type() * \param pointer to array filled by I_signatures_list_by_type() @@ -255,6 +266,7 @@ void I_free_signatures_list(int count, char ***list) G_free((*list)[n]); } G_free(*list); + *list = NULL; } static int list_by_type(I_SIGFILE_TYPE type, const char *mapset, int base, @@ -262,11 +274,11 @@ static int list_by_type(I_SIGFILE_TYPE type, const char *mapset, int base, { int count = 0; char path[GPATH_MAX]; - char element[GNAME_MAX]; + char dir[GNAME_MAX]; char **dirlist; - I__get_signatures_element(element, type); - G_file_name(path, element, "", mapset); + I_get_signatures_dir(dir, type); + G_file_name(path, dir, "", mapset); if (access(path, 0) != 0) { return count; diff --git a/lib/imagery/sigfile.c b/lib/imagery/sigfile.c index 5dd706beb24..f913cbc0d45 100644 --- a/lib/imagery/sigfile.c +++ b/lib/imagery/sigfile.c @@ -17,6 +17,9 @@ /*! \brief Create signature file + Returns a pointer to FILE for writting signature file. + Use fclose on the pointer to close after use. + \param name signature filename \return pointer to FILE @@ -24,14 +27,13 @@ */ FILE *I_fopen_signature_file_new(const char *name) { - char element[GNAME_MAX]; + char dir[GNAME_MAX]; FILE *fd; /* create sig directory */ - I__make_signatures_element(I_SIGFILE_TYPE_SIG); - - I__get_signatures_element(element, I_SIGFILE_TYPE_SIG); - fd = G_fopen_new(element, name); + I_make_signatures_dir(I_SIGFILE_TYPE_SIG); + I_get_signatures_dir(dir, I_SIGFILE_TYPE_SIG); + fd = G_fopen_new_misc(dir, "sig", name); return fd; } @@ -39,7 +41,10 @@ FILE *I_fopen_signature_file_new(const char *name) /*! \brief Open existing signature file - Use fully qualified names for signatures from other mapsets + Use fully qualified names for signatures from other mapsets. + + Returns a pointer to FILE with signature. Use fclose on the pointer + after use. \param name signature filename @@ -49,14 +54,14 @@ FILE *I_fopen_signature_file_new(const char *name) FILE *I_fopen_signature_file_old(const char *name) { char sig_name[GNAME_MAX], sig_mapset[GMAPSET_MAX]; - char element[GNAME_MAX]; + char dir[GNAME_MAX]; FILE *fd; if (G_unqualified_name(name, NULL, sig_name, sig_mapset) == 0) strcpy(sig_mapset, G_mapset()); - I__get_signatures_element(element, I_SIGFILE_TYPE_SIG); - fd = G_fopen_old(element, sig_name, sig_mapset); + I_get_signatures_dir(dir, I_SIGFILE_TYPE_SIG); + fd = G_fopen_old_misc(dir, "sig", sig_name, sig_mapset); return fd; } diff --git a/lib/imagery/sigsetfile.c b/lib/imagery/sigsetfile.c index 279dda2307d..20cd6c9df10 100644 --- a/lib/imagery/sigsetfile.c +++ b/lib/imagery/sigsetfile.c @@ -27,14 +27,14 @@ */ FILE *I_fopen_sigset_file_new(const char *name) { - char element[GNAME_MAX]; + char dir[GNAME_MAX]; FILE *fd; /* create sig directory */ - I__make_signatures_element(I_SIGFILE_TYPE_SIGSET); + I_make_signatures_dir(I_SIGFILE_TYPE_SIGSET); - I__get_signatures_element(element, I_SIGFILE_TYPE_SIGSET); - fd = G_fopen_new(element, name); + I_get_signatures_dir(dir, I_SIGFILE_TYPE_SIGSET); + fd = G_fopen_new_misc(dir, "sig", name); return fd; } @@ -50,14 +50,14 @@ FILE *I_fopen_sigset_file_new(const char *name) FILE *I_fopen_sigset_file_old(const char *name) { char sig_name[GNAME_MAX], sig_mapset[GMAPSET_MAX]; - char element[GNAME_MAX]; + char dir[GNAME_MAX]; FILE *fd; if (G_unqualified_name(name, NULL, sig_name, sig_mapset) == 0) strcpy(sig_mapset, G_mapset()); - I__get_signatures_element(element, I_SIGFILE_TYPE_SIGSET); - fd = G_fopen_old(element, sig_name, sig_mapset); + I_get_signatures_dir(dir, I_SIGFILE_TYPE_SIGSET); + fd = G_fopen_old_misc(dir, "sig", sig_name, sig_mapset); return fd; } diff --git a/lib/imagery/testsuite/test_imagery_find.py b/lib/imagery/testsuite/test_imagery_find.py index 7937ba93888..479eba62a28 100644 --- a/lib/imagery/testsuite/test_imagery_find.py +++ b/lib/imagery/testsuite/test_imagery_find.py @@ -9,6 +9,7 @@ for details """ import os +import shutil from grass.gunittest.case import TestCase from grass.gunittest.main import test @@ -31,24 +32,26 @@ class FindSignatureTestCase(TestCase): def setUpClass(cls): cls.mpath = utils.decode(G_mapset_path()) cls.mapset_name = Mapset().name + cls.sigdirs = [] # As signatures are created directly not via signature creation # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) os.makedirs(f"{cls.mpath}/signatures/sigset/", exist_ok=True) cls.sig_name1 = tempname(10) - cls.sigfile_name1 = f"{cls.mpath}/signatures/sigset/{cls.sig_name1}" - open(cls.sigfile_name1, "a").close() + cls.sig_dir1 = f"{cls.mpath}/signatures/sigset/{cls.sig_name1}" + os.makedirs(cls.sig_dir1) + cls.sigdirs.append(cls.sig_dir1) + open(f"{cls.sig_dir1}/sig", "a").close() cls.sig_name2 = tempname(10) - cls.sigfile_name2 = f"{cls.mpath}/signatures/sig/{cls.sig_name2}" - open(cls.sigfile_name2, "a").close() + cls.sig_dir2 = f"{cls.mpath}/signatures/sig/{cls.sig_name2}" + os.makedirs(cls.sig_dir2) + cls.sigdirs.append(cls.sig_dir2) + open(f"{cls.sig_dir2}/sig", "a").close() @classmethod def tearDownClass(cls): - try: - os.remove(cls.sigfile_name1) - os.remove(cls.sigfile_name2) - except OSError: - pass + for d in cls.sigdirs: + shutil.rmtree(d, ignore_errors=True) def test_find_sig(self): # Non existing without a mapset diff --git a/lib/imagery/testsuite/test_imagery_sigfile.py b/lib/imagery/testsuite/test_imagery_sigfile.py index 40fd1261711..a113a5c613d 100644 --- a/lib/imagery/testsuite/test_imagery_sigfile.py +++ b/lib/imagery/testsuite/test_imagery_sigfile.py @@ -11,6 +11,7 @@ import os import stat import ctypes +import shutil from grass.gunittest.case import TestCase from grass.gunittest.main import test @@ -45,14 +46,11 @@ def setUpClass(cls): cls.mpath = utils.decode(G_mapset_path()) cls.mapset_name = Mapset().name cls.sig_name = tempname(10) - cls.sigfile_name = f"{cls.mpath}/signatures/sig/{cls.sig_name}" + cls.sig_dir = f"{cls.mpath}/signatures/sig/{cls.sig_name}" @classmethod def tearDownClass(cls): - try: - os.remove(cls.sigfile_name) - except OSError: - pass + shutil.rmtree(cls.sig_dir, ignore_errors=True) def test_I_fopen_signature_file_old_fail(self): sigfile = I_fopen_signature_file_old(tempname(10)) @@ -81,7 +79,7 @@ def test_roundtrip_signature_v1_norgb_one_band(self): # Write signatures to file p_new_sigfile = I_fopen_signature_file_new(self.sig_name) - sig_stat = os.stat(self.sigfile_name) + sig_stat = os.stat(f"{self.sig_dir}/sig") self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_write_signatures(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) @@ -134,7 +132,7 @@ def test_broken_signature_v1_norgb(self): # Write signatures to file p_new_sigfile = I_fopen_signature_file_new(self.sig_name) - sig_stat = os.stat(self.sigfile_name) + sig_stat = os.stat(f"{self.sig_dir}/sig") self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_write_signatures(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) @@ -186,7 +184,7 @@ def test_roundtrip_signature_v1_norgb_two_bands(self): # Write signatures to file p_new_sigfile = I_fopen_signature_file_new(self.sig_name) - sig_stat = os.stat(self.sigfile_name) + sig_stat = os.stat(f"{self.sig_dir}/sig") self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_write_signatures(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) diff --git a/lib/imagery/testsuite/test_imagery_signature_management.py b/lib/imagery/testsuite/test_imagery_signature_management.py index 7ed4882911d..ae926afd6e8 100644 --- a/lib/imagery/testsuite/test_imagery_signature_management.py +++ b/lib/imagery/testsuite/test_imagery_signature_management.py @@ -36,21 +36,21 @@ I_signatures_rename, I_signatures_list_by_type, I_free_signatures_list, - I__get_signatures_element, - I__make_signatures_element, + I_get_signatures_dir, + I_make_signatures_dir, ) class GetSignaturesElementTestCase(TestCase): def test_get_sig(self): - elem = ctypes.create_string_buffer(GNAME_MAX) - I__get_signatures_element(elem, I_SIGFILE_TYPE_SIG) - self.assertEqual(utils.decode(elem.value), f"signatures{HOST_DIRSEP}sig") + cdir = ctypes.create_string_buffer(GNAME_MAX) + I_get_signatures_dir(cdir, I_SIGFILE_TYPE_SIG) + self.assertEqual(utils.decode(cdir.value), f"signatures{HOST_DIRSEP}sig") def test_get_sigset(self): - elem = ctypes.create_string_buffer(GNAME_MAX) - I__get_signatures_element(elem, I_SIGFILE_TYPE_SIGSET) - self.assertEqual(utils.decode(elem.value), f"signatures{HOST_DIRSEP}sigset") + cdir = ctypes.create_string_buffer(GNAME_MAX) + I_get_signatures_dir(cdir, I_SIGFILE_TYPE_SIGSET) + self.assertEqual(utils.decode(cdir.value), f"signatures{HOST_DIRSEP}sigset") class MakeSignaturesElementTestCase(TestCase): @@ -69,23 +69,23 @@ def tearDownClass(cls): shutil.rmtree(cls.tmp_mapset_path, ignore_errors=True) def test_make_sig(self): - I__make_signatures_element(I_SIGFILE_TYPE_SIG) + I_make_signatures_dir(I_SIGFILE_TYPE_SIG) self.assertTrue( os.path.isdir(os.path.join(self.tmp_mapset_path, "signatures", "sig")) ) # There should not be any side effects of calling function multiple times - I__make_signatures_element(I_SIGFILE_TYPE_SIG) + I_make_signatures_dir(I_SIGFILE_TYPE_SIG) self.assertTrue( os.path.isdir(os.path.join(self.tmp_mapset_path, "signatures", "sig")) ) def test_make_sigset(self): - I__make_signatures_element(I_SIGFILE_TYPE_SIGSET) + I_make_signatures_dir(I_SIGFILE_TYPE_SIGSET) self.assertTrue( os.path.isdir(os.path.join(self.tmp_mapset_path, "signatures", "sigset")) ) # There should not be any side effects of calling function multiple times - I__make_signatures_element(I_SIGFILE_TYPE_SIGSET) + I_make_signatures_dir(I_SIGFILE_TYPE_SIGSET) self.assertTrue( os.path.isdir(os.path.join(self.tmp_mapset_path, "signatures", "sigset")) ) @@ -96,7 +96,7 @@ class SignaturesRemoveTestCase(TestCase): def setUpClass(cls): cls.mpath = utils.decode(G_mapset_path()) cls.mapset_name = Mapset().name - cls.sigfiles = [] + cls.sigdirs = [] # As signatures are created directly not via signature creation # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) @@ -104,27 +104,30 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - for f in cls.sigfiles: - try: - os.remove(f) - except OSError: - pass + for d in cls.sigdirs: + shutil.rmtree(d, ignore_errors=True) def test_remove_existing_sig(self): # This test will fail if run in PERMANENT! # Set up files and mark for clean-up sig_name1 = tempname(10) - sigfile_name1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + sig_dir1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + os.makedirs(sig_dir1) + self.sigdirs.append(sig_dir1) + sigfile_name1 = f"{sig_dir1}/sig" open(sigfile_name1, "a").close() - self.sigfiles.append(sigfile_name1) sig_name2 = tempname(10) - sigfile_name2 = f"{self.mpath}/signatures/sig/{sig_name2}" + sig_dir2 = f"{self.mpath}/signatures/sig/{sig_name2}" + os.makedirs(sig_dir2) + self.sigdirs.append(sig_dir2) + sigfile_name2 = f"{sig_dir2}/sig" open(sigfile_name2, "a").close() - self.sigfiles.append(sigfile_name2) sig_name3 = tempname(10) - sigfile_name3 = f"{self.mpath}/signatures/sig/{sig_name3}" + sig_dir3 = f"{self.mpath}/signatures/sig/{sig_name3}" + os.makedirs(sig_dir3) + self.sigdirs.append(sig_dir3) + sigfile_name3 = f"{sig_dir3}/sig" open(sigfile_name3, "a").close() - self.sigfiles.append(sigfile_name3) # Try to remove with wrong type ret = I_signatures_remove(I_SIGFILE_TYPE_SIGSET, sig_name2) self.assertEqual(ret, 1) @@ -155,15 +158,19 @@ def test_remove_existing_sig(self): def test_remove_nonexisting_sig(self): # Set up files and mark for clean-up sig_name1 = tempname(10) - sigfile_name1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + sig_dir1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + os.makedirs(sig_dir1) + self.sigdirs.append(sig_dir1) + sigfile_name1 = f"{sig_dir1}/sig" open(sigfile_name1, "a").close() - self.sigfiles.append(sigfile_name1) sig_name2 = tempname(10) # Do not create sig_name2 matching file sig_name3 = tempname(10) - sigfile_name3 = f"{self.mpath}/signatures/sig/{sig_name3}" + sig_dir3 = f"{self.mpath}/signatures/sig/{sig_name3}" + os.makedirs(sig_dir3) + self.sigdirs.append(sig_dir3) + sigfile_name3 = f"{sig_dir3}/sig" open(sigfile_name3, "a").close() - self.sigfiles.append(sigfile_name3) # Now remove one (should fail as file is absent) ret = I_signatures_remove(I_SIGFILE_TYPE_SIG, sig_name2) self.assertEqual(ret, 1) @@ -183,17 +190,23 @@ def test_remove_nonexisting_sig(self): def test_remove_existing_sigset(self): # Set up files and mark for clean-up sig_name1 = tempname(10) - sigfile_name1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + sig_dir1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + os.makedirs(sig_dir1) + self.sigdirs.append(sig_dir1) + sigfile_name1 = f"{sig_dir1}/sig" open(sigfile_name1, "a").close() - self.sigfiles.append(sigfile_name1) sig_name2 = tempname(10) - sigfile_name2 = f"{self.mpath}/signatures/sigset/{sig_name2}" + sig_dir2 = f"{self.mpath}/signatures/sigset/{sig_name2}" + os.makedirs(sig_dir2) + self.sigdirs.append(sig_dir2) + sigfile_name2 = f"{sig_dir2}/sig" open(sigfile_name2, "a").close() - self.sigfiles.append(sigfile_name2) sig_name3 = tempname(10) - sigfile_name3 = f"{self.mpath}/signatures/sig/{sig_name3}" + sig_dir3 = f"{self.mpath}/signatures/sig/{sig_name3}" + os.makedirs(sig_dir3) + self.sigdirs.append(sig_dir3) + sigfile_name3 = f"{sig_dir3}/sig" open(sigfile_name3, "a").close() - self.sigfiles.append(sigfile_name3) # Try to remove with wrong type ret = I_signatures_remove(I_SIGFILE_TYPE_SIG, sig_name2) self.assertEqual(ret, 1) @@ -224,15 +237,19 @@ def test_remove_existing_sigset(self): def test_remove_nonexisting_sigset(self): # Set up files and mark for clean-up sig_name1 = tempname(10) - sigfile_name1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + sig_dir1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + os.makedirs(sig_dir1) + self.sigdirs.append(sig_dir1) + sigfile_name1 = f"{sig_dir1}/sig" open(sigfile_name1, "a").close() - self.sigfiles.append(sigfile_name1) sig_name2 = tempname(10) # Do not create sig_name2 matching file sig_name3 = tempname(10) - sigfile_name3 = f"{self.mpath}/signatures/sig/{sig_name3}" + sig_dir3 = f"{self.mpath}/signatures/sig/{sig_name3}" + os.makedirs(sig_dir3) + self.sigdirs.append(sig_dir3) + sigfile_name3 = f"{sig_dir3}/sig" open(sigfile_name3, "a").close() - self.sigfiles.append(sigfile_name3) # Now remove one (should fail as file doesn't exist) ret = I_signatures_remove(I_SIGFILE_TYPE_SIGSET, sig_name2) self.assertEqual(ret, 1) @@ -255,7 +272,7 @@ class SignaturesCopyTestCase(TestCase): def setUpClass(cls): cls.mpath = utils.decode(G_mapset_path()) cls.mapset_name = Mapset().name - cls.sigfiles = [] + cls.sigdirs = [] # As signatures are created directly not via signature creation # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) @@ -266,16 +283,21 @@ def setUpClass(cls): cls.src_mapset_path = ( cls.mpath.rsplit("/", maxsplit=1)[0] + "/" + cls.src_mapset_name ) + # Create fake signature files os.makedirs(f"{cls.src_mapset_path}/signatures/sig/") cls.src_sig = tempname(10) - cls.sigfiles.append(f"{cls.src_mapset_path}/signatures/sig/{cls.src_sig}") - f = open(cls.sigfiles[0], "w") + cls.src_sig_dir = f"{cls.src_mapset_path}/signatures/sig/{cls.src_sig}" + os.makedirs(cls.src_sig_dir) + cls.sigdirs.append(cls.src_sig_dir) + f = open(f"{cls.src_sig_dir}/sig", "w") f.write("A sig file") f.close() os.makedirs(f"{cls.src_mapset_path}/signatures/sigset/") cls.src_sigset = tempname(10) - cls.sigfiles.append(f"{cls.src_mapset_path}/signatures/sigset/{cls.src_sigset}") - f = open(cls.sigfiles[1], "w") + cls.src_sigset_dir = f"{cls.src_mapset_path}/signatures/sigset/{cls.src_sigset}" + os.makedirs(cls.src_sigset_dir) + cls.sigdirs.append(cls.src_sigset_dir) + f = open(f"{cls.src_sigset_dir}/sig", "w") f.write("A sigset file") f.close() @@ -283,11 +305,8 @@ def setUpClass(cls): def tearDownClass(cls): # Remove random mapset created during setup shutil.rmtree(cls.src_mapset_path, ignore_errors=True) - for f in cls.sigfiles: - try: - os.remove(f) - except OSError: - pass + for d in cls.sigdirs: + shutil.rmtree(d, ignore_errors=True) def test_copy_to_wrong_mapset(self): rnd_name = "{0}@{0}".format(tempname(10)) @@ -317,17 +336,18 @@ def test_success_unqualified_sig(self): ret = I_signatures_copy( I_SIGFILE_TYPE_SIG, self.src_sig, self.src_mapset_name, dst ) - self.sigfiles.append(f"{self.mpath}/signatures/sig/{dst}") + self.sigdirs.append(f"{self.mpath}/signatures/sig/{dst}") self.assertEqual(ret, 0) ret = I_find_signature(I_SIGFILE_TYPE_SIG, dst, self.mapset_name) self.assertTrue(ret) ms = utils.decode(ret) self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{self.mpath}/signatures/sig/{dst}/sig")) def test_success_fq_sig(self): - dst = tempname(10) - self.sigfiles.append(f"{self.mpath}/signatures/sig/{dst}") - dst = dst + "@" + self.mapset_name + dst_name = tempname(10) + self.sigdirs.append(f"{self.mpath}/signatures/sig/{dst_name}") + dst = dst_name + "@" + self.mapset_name ret = I_find_signature(I_SIGFILE_TYPE_SIG, dst, self.mapset_name) self.assertFalse(ret) ret = I_find_signature(I_SIGFILE_TYPE_SIG, self.src_sig, self.src_mapset_name) @@ -343,6 +363,7 @@ def test_success_fq_sig(self): self.assertTrue(ret) ms = utils.decode(ret) self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{self.mpath}/signatures/sig/{dst_name}/sig")) def test_success_unqualified_sigset(self): dst = tempname(10) @@ -355,17 +376,18 @@ def test_success_unqualified_sigset(self): ret = I_signatures_copy( I_SIGFILE_TYPE_SIGSET, self.src_sigset, self.src_mapset_name, dst ) - self.sigfiles.append(f"{self.mpath}/signatures/sigset/{dst}") + self.sigdirs.append(f"{self.mpath}/signatures/sigset/{dst}") self.assertEqual(ret, 0) ret = I_find_signature(I_SIGFILE_TYPE_SIGSET, dst, self.mapset_name) self.assertTrue(ret) ms = utils.decode(ret) self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{self.mpath}/signatures/sigset/{dst}/sig")) def test_success_fq_sigset(self): - dst = tempname(10) - self.sigfiles.append(f"{self.mpath}/signatures/sigset/{dst}") - dst = dst + "@" + self.mapset_name + dst_name = tempname(10) + self.sigdirs.append(f"{self.mpath}/signatures/sigset/{dst_name}") + dst = dst_name + "@" + self.mapset_name ret = I_find_signature(I_SIGFILE_TYPE_SIGSET, dst, self.mapset_name) self.assertFalse(ret) ret = I_find_signature( @@ -383,6 +405,9 @@ def test_success_fq_sigset(self): self.assertTrue(ret) ms = utils.decode(ret) self.assertEqual(ms, self.mapset_name) + self.assertTrue( + os.path.isfile(f"{self.mpath}/signatures/sigset/{dst_name}/sig") + ) class SignaturesRenameTestCase(TestCase): @@ -390,7 +415,7 @@ class SignaturesRenameTestCase(TestCase): def setUpClass(cls): cls.mpath = utils.decode(G_mapset_path()) cls.mapset_name = Mapset().name - cls.sigfiles = [] + cls.sigdirs = [] # As signatures are created directly not via signature creation # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) @@ -398,11 +423,8 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - for f in cls.sigfiles: - try: - os.remove(f) - except OSError: - pass + for d in cls.sigdirs: + shutil.rmtree(d, ignore_errors=True) def test_rename_from_wrong_mapset(self): rnd_name = "{0}@{0}".format(tempname(10)) @@ -424,13 +446,14 @@ def test_sigset_does_not_exist(self): def test_success_unqualified_sig(self): src_sig = tempname(10) - sig_file = f"{self.mpath}/signatures/sig/{src_sig}" - self.sigfiles.append(sig_file) - f = open(sig_file, "w") + sig_dir = f"{self.mpath}/signatures/sig/{src_sig}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") f.write("A sig file") f.close() dst = tempname(10) - self.sigfiles.append(f"{self.mpath}/signatures/sig/{dst}") + self.sigdirs.append(f"{self.mpath}/signatures/sig/{dst}") ret = I_find_signature(I_SIGFILE_TYPE_SIG, dst, self.mapset_name) self.assertFalse(ret) ret = I_find_signature(I_SIGFILE_TYPE_SIG, src_sig, self.mapset_name) @@ -441,17 +464,19 @@ def test_success_unqualified_sig(self): self.assertTrue(ret) ms = utils.decode(ret) self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{self.mpath}/signatures/sig/{dst}/sig")) def test_success_fq_sig(self): src_sig = tempname(10) - sig_file = f"{self.mpath}/signatures/sig/{src_sig}" - self.sigfiles.append(sig_file) - f = open(sig_file, "w") + sig_dir = f"{self.mpath}/signatures/sig/{src_sig}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") f.write("A sig file") f.close() - dst = tempname(10) - self.sigfiles.append(f"{self.mpath}/signatures/sig/{dst}") - dst = dst + "@" + self.mapset_name + dst_name = tempname(10) + self.sigdirs.append(f"{self.mpath}/signatures/sig/{dst_name}") + dst = dst_name + "@" + self.mapset_name ret = I_find_signature(I_SIGFILE_TYPE_SIG, dst, self.mapset_name) self.assertFalse(ret) ret = I_find_signature(I_SIGFILE_TYPE_SIG, src_sig, self.mapset_name) @@ -466,16 +491,18 @@ def test_success_fq_sig(self): self.assertTrue(ret) ms = utils.decode(ret) self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{self.mpath}/signatures/sig/{dst_name}/sig")) def test_success_unqualified_sigset(self): src_sigset = tempname(10) - sigset_file = f"{self.mpath}/signatures/sigset/{src_sigset}" - self.sigfiles.append(sigset_file) - f = open(sigset_file, "w") + sig_dir = f"{self.mpath}/signatures/sigset/{src_sigset}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") f.write("A sigset file") f.close() dst = tempname(10) - self.sigfiles.append(f"{self.mpath}/signatures/sigset/{dst}") + self.sigdirs.append(f"{self.mpath}/signatures/sigset/{dst}") ret = I_find_signature(I_SIGFILE_TYPE_SIGSET, dst, self.mapset_name) self.assertFalse(ret) ret = I_find_signature(I_SIGFILE_TYPE_SIGSET, src_sigset, self.mapset_name) @@ -486,17 +513,19 @@ def test_success_unqualified_sigset(self): self.assertTrue(ret) ms = utils.decode(ret) self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{self.mpath}/signatures/sigset/{dst}/sig")) def test_success_fq_sigset(self): src_sigset = tempname(10) - sigset_file = f"{self.mpath}/signatures/sigset/{src_sigset}" - self.sigfiles.append(sigset_file) - f = open(sigset_file, "w") + sig_dir = f"{self.mpath}/signatures/sigset/{src_sigset}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") f.write("A sigset file") f.close() - dst = tempname(10) - self.sigfiles.append(f"{self.mpath}/signatures/sigset/{dst}") - dst = dst + "@" + self.mapset_name + dst_name = tempname(10) + self.sigdirs.append(f"{self.mpath}/signatures/sigset/{dst_name}") + dst = dst_name + "@" + self.mapset_name ret = I_find_signature(I_SIGFILE_TYPE_SIGSET, dst, self.mapset_name) self.assertFalse(ret) ret = I_find_signature(I_SIGFILE_TYPE_SIGSET, src_sigset, self.mapset_name) @@ -511,6 +540,9 @@ def test_success_fq_sigset(self): self.assertTrue(ret) ms = utils.decode(ret) self.assertEqual(ms, self.mapset_name) + self.assertTrue( + os.path.isfile(f"{self.mpath}/signatures/sigset/{dst_name}/sig") + ) class SignaturesListByTypeTestCase(TestCase): @@ -519,7 +551,7 @@ def setUpClass(cls): cls.list_ptr = ctypes.POINTER(ctypes.c_char_p) cls.mpath = utils.decode(G_mapset_path()) cls.mapset_name = Mapset().name - cls.sigfiles = [] + cls.sigdirs = [] # As signatures are created directly not via signature creation # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) @@ -537,11 +569,8 @@ def setUpClass(cls): def tearDownClass(cls): # Remove random mapset created during setup shutil.rmtree(cls.rnd_mapset_path, ignore_errors=True) - for f in cls.sigfiles: - try: - os.remove(f) - except OSError: - pass + for d in cls.sigdirs: + shutil.rmtree(d, ignore_errors=True) def test_no_sigs_at_all(self): # There should be no signatures in the mapset with random @@ -552,63 +581,78 @@ def test_no_sigs_at_all(self): ) self.assertEqual(ret, 0) I_free_signatures_list(ret, ctypes.byref(sig_list)) + ret = I_signatures_list_by_type( + I_SIGFILE_TYPE_SIGSET, self.rnd_mapset_name, ctypes.byref(sig_list) + ) + self.assertEqual(ret, 0) + I_free_signatures_list(ret, ctypes.byref(sig_list)) def test_sig_in_different_mapset(self): # Should return 0 signatures from a different mapset + # Sig type local_sig = tempname(10) - sig_file = f"{self.mpath}/signatures/sig/{local_sig}" - self.sigfiles.append(sig_file) - f = open(sig_file, "w") + sig_dir = f"{self.mpath}/signatures/sig/{local_sig}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") f.write("A sig file") f.close() sig_list = self.list_ptr() ret = I_signatures_list_by_type( I_SIGFILE_TYPE_SIG, self.rnd_mapset_name, ctypes.byref(sig_list) ) - os.remove(sig_file) + shutil.rmtree(sig_dir) self.assertEqual(ret, 0) I_free_signatures_list(ret, ctypes.byref(sig_list)) + # SigSet type local_sigset = tempname(10) - sigset_file = f"{self.mpath}/signatures/sigset/{local_sigset}" - self.sigfiles.append(sigset_file) - f = open(sigset_file, "w") + sig_dir = f"{self.mpath}/signatures/sigset/{local_sigset}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") f.write("A sigset file") f.close() sig_list = self.list_ptr() ret = I_signatures_list_by_type( I_SIGFILE_TYPE_SIGSET, self.rnd_mapset_name, ctypes.byref(sig_list) ) - os.remove(sigset_file) + shutil.rmtree(sig_dir) self.assertEqual(ret, 0) I_free_signatures_list(ret, ctypes.byref(sig_list)) def test_single_sig(self): # Case when only a single signature file is present + # Sig type rnd_sig = tempname(10) - sig_file = f"{self.rnd_mapset_path}/signatures/sig/{rnd_sig}" - f = open(sig_file, "w") + sig_dir = f"{self.rnd_mapset_path}/signatures/sig/{rnd_sig}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") f.write("A sig file") f.close() sig_list = self.list_ptr() ret = I_signatures_list_by_type( I_SIGFILE_TYPE_SIG, self.rnd_mapset_name, ctypes.byref(sig_list) ) - os.remove(sig_file) + shutil.rmtree(sig_dir) self.assertEqual(ret, 1) val = utils.decode(sig_list[0]) self.assertEqual(val, f"{rnd_sig}@{self.rnd_mapset_name}") I_free_signatures_list(ret, ctypes.byref(sig_list)) + # SigSet type # SigSet equals sig. Just testing branching inside. rnd_sigset = tempname(10) - sigset_file = f"{self.rnd_mapset_path}/signatures/sigset/{rnd_sigset}" - f = open(sigset_file, "w") + sig_dir = f"{self.rnd_mapset_path}/signatures/sigset/{rnd_sigset}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") f.write("A sigset file") f.close() sigset_list = self.list_ptr() ret = I_signatures_list_by_type( I_SIGFILE_TYPE_SIGSET, self.rnd_mapset_name, ctypes.byref(sigset_list) ) - os.remove(sigset_file) + shutil.rmtree(sig_dir) self.assertEqual(ret, 1) val = utils.decode(sigset_list[0]) self.assertEqual(val, f"{rnd_sigset}@{self.rnd_mapset_name}") @@ -616,14 +660,19 @@ def test_single_sig(self): def test_multiple_sigs(self): # Should result into a multiple sigs returned + # Sig type rnd_sig1 = tempname(10) - sig_file1 = f"{self.rnd_mapset_path}/signatures/sig/{rnd_sig1}" - f = open(sig_file1, "w") + sig_dir1 = f"{self.rnd_mapset_path}/signatures/sig/{rnd_sig1}" + os.makedirs(sig_dir1) + self.sigdirs.append(sig_dir1) + f = open(f"{sig_dir1}/sig", "w") f.write("A sig file") f.close() rnd_sig2 = tempname(10) - sig_file2 = f"{self.rnd_mapset_path}/signatures/sig/{rnd_sig2}" - f = open(sig_file2, "w") + sig_dir2 = f"{self.rnd_mapset_path}/signatures/sig/{rnd_sig2}" + os.makedirs(sig_dir2) + self.sigdirs.append(sig_dir2) + f = open(f"{sig_dir2}/sig", "w") f.write("A sig file") f.close() # POINTER(POINTER(c_char)) @@ -631,8 +680,8 @@ def test_multiple_sigs(self): ret = I_signatures_list_by_type( I_SIGFILE_TYPE_SIG, self.rnd_mapset_name, ctypes.byref(sig_list) ) - os.remove(sig_file1) - os.remove(sig_file2) + shutil.rmtree(sig_dir1) + shutil.rmtree(sig_dir2) self.assertEqual(ret, 2) golden = ( f"{rnd_sig1}@{self.rnd_mapset_name}", @@ -641,23 +690,27 @@ def test_multiple_sigs(self): self.assertIn(utils.decode(sig_list[0]), golden) self.assertIn(utils.decode(sig_list[1]), golden) I_free_signatures_list(ret, ctypes.byref(sig_list)) - # Ditto for sigset + # SigSet type rnd_sigset1 = tempname(10) - sigset_file1 = f"{self.rnd_mapset_path}/signatures/sigset/{rnd_sigset1}" - f = open(sigset_file1, "w") + sig_dir1 = f"{self.rnd_mapset_path}/signatures/sigset/{rnd_sigset1}" + os.makedirs(sig_dir1) + self.sigdirs.append(sig_dir1) + f = open(f"{sig_dir1}/sig", "w") f.write("A sigset file") f.close() rnd_sigset2 = tempname(10) - sigset_file2 = f"{self.rnd_mapset_path}/signatures/sigset/{rnd_sigset2}" - f = open(sigset_file2, "w") + sig_dir2 = f"{self.rnd_mapset_path}/signatures/sigset/{rnd_sigset2}" + os.makedirs(sig_dir2) + self.sigdirs.append(sig_dir2) + f = open(f"{sig_dir2}/sig", "w") f.write("A sigset file") f.close() sigset_list = self.list_ptr() ret = I_signatures_list_by_type( I_SIGFILE_TYPE_SIGSET, self.rnd_mapset_name, ctypes.byref(sigset_list) ) - os.remove(sigset_file1) - os.remove(sigset_file2) + shutil.rmtree(sig_dir1) + shutil.rmtree(sig_dir2) self.assertEqual(ret, 2) golden = ( f"{rnd_sigset1}@{self.rnd_mapset_name}", @@ -670,16 +723,19 @@ def test_multiple_sigs(self): def test_multiple_sigs_multiple_mapsets(self): # Test searching in multiple mapsets. Identical to SIGSET case rnd_sig1 = tempname(10) - sig_file1 = f"{self.rnd_mapset_path}/signatures/sig/{rnd_sig1}" - f = open(sig_file1, "w") + sig_dir1 = f"{self.rnd_mapset_path}/signatures/sig/{rnd_sig1}" + os.makedirs(sig_dir1) + self.sigdirs.append(sig_dir1) + f = open(f"{sig_dir1}/sig", "w") f.write("A sig file") f.close() rnd_sig2 = tempname(10) - sig_file2 = f"{self.mpath}/signatures/sig/{rnd_sig2}" - f = open(sig_file2, "w") + sig_dir2 = f"{self.mpath}/signatures/sig/{rnd_sig2}" + os.makedirs(sig_dir2) + self.sigdirs.append(sig_dir2) + f = open(f"{sig_dir2}/sig", "w") f.write("A sig file") f.close() - self.sigfiles.append(sig_file2) sig_list = self.list_ptr() ret = I_signatures_list_by_type( I_SIGFILE_TYPE_SIG, None, ctypes.byref(sig_list) @@ -706,8 +762,8 @@ def test_multiple_sigs_multiple_mapsets(self): ) grass.run_command("g.mapsets", mapset=self.rnd_mapset_name, operation="remove") G_reset_mapsets() - os.remove(sig_file1) - os.remove(sig_file2) + shutil.rmtree(sig_dir1) + shutil.rmtree(sig_dir2) # There could be more sigs if this is not an empty mapset self.assertTrue(ret >= 2) ret_list = list(map(utils.decode, sig_list[:ret])) @@ -718,16 +774,19 @@ def test_multiple_sigs_multiple_mapsets(self): def test_multiple_sigsets_multiple_mapsets(self): # Test searching in multiple mapsets. Identical to SIG case rnd_sig1 = tempname(10) - sig_file1 = f"{self.rnd_mapset_path}/signatures/sigset/{rnd_sig1}" - f = open(sig_file1, "w") + sig_dir1 = f"{self.rnd_mapset_path}/signatures/sigset/{rnd_sig1}" + os.makedirs(sig_dir1) + self.sigdirs.append(sig_dir1) + f = open(f"{sig_dir1}/sig", "w") f.write("A sigset file") f.close() rnd_sig2 = tempname(10) - sig_file2 = f"{self.mpath}/signatures/sigset/{rnd_sig2}" - f = open(sig_file2, "w") + sig_dir2 = f"{self.mpath}/signatures/sigset/{rnd_sig2}" + os.makedirs(sig_dir2) + self.sigdirs.append(sig_dir2) + f = open(f"{sig_dir2}/sig", "w") f.write("A sigset file") f.close() - self.sigfiles.append(sig_file2) sig_list = self.list_ptr() ret = I_signatures_list_by_type( I_SIGFILE_TYPE_SIGSET, None, ctypes.byref(sig_list) @@ -754,8 +813,8 @@ def test_multiple_sigsets_multiple_mapsets(self): ) grass.run_command("g.mapsets", mapset=self.rnd_mapset_name, operation="remove") G_reset_mapsets() - os.remove(sig_file1) - os.remove(sig_file2) + shutil.rmtree(sig_dir1) + shutil.rmtree(sig_dir2) # There could be more sigs if this is not an empty mapset self.assertTrue(ret >= 2) ret_list = list(map(utils.decode, sig_list[:ret])) diff --git a/lib/imagery/testsuite/test_imagery_sigsetfile.py b/lib/imagery/testsuite/test_imagery_sigsetfile.py index c10ff8379cd..704631be6fc 100644 --- a/lib/imagery/testsuite/test_imagery_sigsetfile.py +++ b/lib/imagery/testsuite/test_imagery_sigsetfile.py @@ -11,6 +11,7 @@ import os import stat import ctypes +import shutil from grass.gunittest.case import TestCase from grass.gunittest.main import test @@ -46,14 +47,11 @@ def setUpClass(cls): cls.mpath = utils.decode(G_mapset_path()) cls.mapset_name = Mapset().name cls.sig_name = tempname(10) - cls.sigfile_name = f"{cls.mpath}/signatures/sigset/{cls.sig_name}" + cls.sig_dir = f"{cls.mpath}/signatures/sigset/{cls.sig_name}" @classmethod def tearDownClass(cls): - try: - os.remove(cls.sigfile_name) - except OSError: - pass + shutil.rmtree(cls.sig_dir, ignore_errors=True) def test_I_fopen_signature_file_old_fail(self): sigfile = I_fopen_sigset_file_old(tempname(10)) @@ -85,7 +83,7 @@ def test_roundtrip_sigset_v1_one_band(self): # Write signatures to file p_new_sigfile = I_fopen_sigset_file_new(self.sig_name) - sig_stat = os.stat(self.sigfile_name) + sig_stat = os.stat(f"{self.sig_dir}/sig") self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_WriteSigSet(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) @@ -138,7 +136,7 @@ def test_read_fail_sigset_v1_one_band(self): # Write signatures to file p_new_sigfile = I_fopen_sigset_file_new(self.sig_name) - sig_stat = os.stat(self.sigfile_name) + sig_stat = os.stat(f"{self.sig_dir}/sig") self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_WriteSigSet(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) @@ -182,7 +180,7 @@ def test_roundtrip_sigset_v1_two_bands(self): # Write signatures to file p_new_sigfile = I_fopen_sigset_file_new(self.sig_name) - sig_stat = os.stat(self.sigfile_name) + sig_stat = os.stat(f"{self.sig_dir}/sig") self.assertTrue(stat.S_ISREG(sig_stat.st_mode)) I_WriteSigSet(p_new_sigfile, ctypes.byref(So)) self.libc.fclose(p_new_sigfile) From 75c925aa8a8c859f3547c1e8b929c228ff1a9325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Thu, 9 Sep 2021 17:09:05 +0300 Subject: [PATCH 002/123] Imagery: correctly free signature list in Python --- gui/wxpython/gui_core/gselect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index 9d047bb2e3a..6fdfd95b124 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -2835,7 +2835,7 @@ def _append_mapset_signatures(self, mapset, sig_type, items): count = I_signatures_list_by_type(sig_type, mapset, ctypes.byref(sig_list)) for n in range(count): items.append(decode(sig_list[n])) - I_free_signatures_list(count, sig_list) + I_free_signatures_list(count, ctypes.byref(sig_list)) class SeparatorSelect(wx.ComboBox): From 5c1a25349eb38bf594e7fde7b019ea6ac0dfd8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Wed, 13 Jan 2021 22:13:57 +0200 Subject: [PATCH 003/123] i.svm.train: Start of module --- imagery/i.svm.train/Makefile | 10 ++ imagery/i.svm.train/main.c | 309 +++++++++++++++++++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 imagery/i.svm.train/Makefile create mode 100644 imagery/i.svm.train/main.c diff --git a/imagery/i.svm.train/Makefile b/imagery/i.svm.train/Makefile new file mode 100644 index 00000000000..a7828026b23 --- /dev/null +++ b/imagery/i.svm.train/Makefile @@ -0,0 +1,10 @@ +MODULE_TOPDIR = ../.. + +PGM = i.svm.train + +LIBES = $(RASTERLIB) $(IMAGERYLIB) $(GISLIB) +DEPENDENCIES = $(RASTERDEP) $(IMAGERYDEP) $(GISDEP) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +default: cmd diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c new file mode 100644 index 00000000000..df4b9344997 --- /dev/null +++ b/imagery/i.svm.train/main.c @@ -0,0 +1,309 @@ + +/**************************************************************************** + * + * MODULE: i.svm.train + * AUTHOR(S): Maris Nartiss - maris.gis gmail.com + * PURPOSE: Trains Support Vector Machine classifier + * + * COPYRIGHT: (C) 2020 by Maris Nartiss and the GRASS Development Team + * + * This program is free software under the GNU General Public + * License (>=v2). Read the file COPYING that comes with GRASS + * for details. + * + *****************************************************************************/ +#include +#include + +#include + +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + struct GModule *module; + struct Option *opt_group, *opt_subgroup, *opt_sigfile; + struct Option *opt_svm_type, *opt_svm_kernel; + struct Option *opt_svm_cache_size, *opt_svm_degree, *opt_svm_gamma, + *opt_svm_coef0, *opt_svm_eps, *opt_svm_cost, *opt_svm_nu, *opt_svm_p; + struct Flag *flag_svm_shrink, *flag_svm_prob; + + struct Ref bands; + + struct svm_parameter parameters; + const char *parameters_error; + + G_gisinit(argv[0]); + + module = G_define_module(); + G_add_keyword(_("imagery")); + G_add_keyword(_("svm")); + G_add_keyword(_("classification")); + G_add_keyword(_("training")); + module->description = _("Train SVM"); + + opt_group = G_define_standard_option(G_OPT_I_GROUP); + + opt_subgroup = G_define_standard_option(G_OPT_I_SUBGROUP); + opt_subgroup->required = NO; + + opt_sigfile = G_define_option(); + opt_sigfile->key = "signaturefile"; + opt_sigfile->type = TYPE_STRING; + opt_sigfile->key_desc = "name"; + opt_sigfile->required = YES; + opt_sigfile->gisprompt = "new,sig,sigfile"; + opt_sigfile->description = + _("Name for output file containing result signatures"); + + opt_svm_type = G_define_option(); + opt_svm_type->key = "type"; + opt_svm_type->type = TYPE_STRING; + opt_svm_type->key_desc = "name"; + opt_svm_type->required = NO; + opt_svm_type->options = "c_svc,nu_svc,one_class,epsilon_svr,nu_svr"; + opt_svm_type->answer = "c_svc"; + opt_svm_type->description = _("Type of SVM"); + opt_svm_type->guisection = _("SVM parameters"); + G_asprintf((char **)&(opt_svm_type->descriptions), + "c_svc;%s;" + "nu_svc;%s;" "one_class;%s;" "epsilon_svr;%s;" "nu_svr;%s;", + /* GTC: SVM type */ + _("C-SVM classification"), + /* GTC: SVM type */ + _("nu-SVM classification"), + /* GTC: SVM type */ + _("one-class SVM"), + /* GTC: SVM type */ + _("epsilon-SVM regression"), + /* GTC: SVM type */ + _("nu-SVM regression")); + + opt_svm_kernel = G_define_option(); + opt_svm_kernel->key = "kernel"; + opt_svm_kernel->type = TYPE_STRING; + opt_svm_kernel->key_desc = "name"; + opt_svm_kernel->required = NO; + opt_svm_kernel->options = "linear,poly,rbf,sigmoid,precomputed"; + opt_svm_kernel->answer = "rbf"; + opt_svm_kernel->description = _("SVM kernel type"); + opt_svm_kernel->guisection = _("SVM parameters"); + G_asprintf((char **)&(opt_svm_kernel->descriptions), + "linear;%s;" + "poly;%s;" "rbf;%s;" "sigmoid;%s;" "precomputed;%s;", + /* GTC: SVM kernel type */ + _("u'*v"), + /* GTC: SVM kernel type */ + _("(gamma*u'*v + coef0)^degree"), + /* GTC: SVM kernel type */ + _("exp(-gamma*|u-v|^2)"), + /* GTC: SVM kernel type */ + _("tanh(gamma*u'*v + coef0)"), + /* GTC: SVM kernel type */ + _("TODO: precomputed")); + + opt_svm_cache_size = G_define_option(); + opt_svm_cache_size->key = "cache"; + opt_svm_cache_size->type = TYPE_INTEGER; + opt_svm_cache_size->key_desc = "cache size"; + opt_svm_cache_size->required = NO; + opt_svm_cache_size->options = "1-999999999"; + opt_svm_cache_size->answer = "512"; + opt_svm_cache_size->description = _("Kernel cache size in MB"); + /* opt_svm_cache_size->guisection = _("SVM options"); */ + + opt_svm_degree = G_define_option(); + opt_svm_degree->key = "degree"; + opt_svm_degree->type = TYPE_INTEGER; + opt_svm_degree->key_desc = "value"; + opt_svm_degree->required = NO; + opt_svm_degree->options = "0-9999"; + opt_svm_degree->answer = "3"; + opt_svm_degree->description = _("Degree in kernel function"); + opt_svm_degree->guisection = _("SVM options"); + + opt_svm_gamma = G_define_option(); + opt_svm_gamma->key = "gamma"; + opt_svm_gamma->type = TYPE_DOUBLE; + opt_svm_gamma->key_desc = "value"; + opt_svm_gamma->required = NO; + opt_svm_gamma->answer = "1"; + opt_svm_gamma->description = _("Gamma in kernel function"); + opt_svm_gamma->guisection = _("SVM options"); + + opt_svm_coef0 = G_define_option(); + opt_svm_coef0->key = "coef0"; + opt_svm_coef0->type = TYPE_DOUBLE; + opt_svm_coef0->key_desc = "value"; + opt_svm_coef0->required = NO; + opt_svm_coef0->answer = "0"; + opt_svm_coef0->description = _("coef0 in kernel function"); + opt_svm_coef0->guisection = _("SVM options"); + + opt_svm_eps = G_define_option(); + opt_svm_eps->key = "eps"; + opt_svm_eps->type = TYPE_DOUBLE; + opt_svm_eps->key_desc = "value"; + opt_svm_eps->required = NO; + /* GTC: SVM epsilon */ + opt_svm_eps->label = _("Tolerance of termination criterion"); + opt_svm_eps->description = + _("Defaults to 0.00001 for nu-SVC and 0.001 for others"); + opt_svm_eps->guisection = _("SVM options"); + + opt_svm_cost = G_define_option(); + opt_svm_cost->key = "cost"; + opt_svm_cost->type = TYPE_DOUBLE; + opt_svm_cost->key_desc = "value"; + opt_svm_cost->required = NO; + opt_svm_cost->answer = "1"; + /* GTC: SVM C */ + opt_svm_cost->label = _("Cost of constraints violation"); + opt_svm_cost->description = + _("The parameter C of C-SVC, epsilon-SVR, and nu-SVR"); + opt_svm_cost->guisection = _("SVM options"); + + opt_svm_nu = G_define_option(); + opt_svm_nu->key = "nu"; + opt_svm_nu->type = TYPE_DOUBLE; + opt_svm_nu->key_desc = "value"; + opt_svm_nu->required = NO; + opt_svm_nu->answer = "0.5"; + opt_svm_nu->description = + _("The parameter nu of nu-SVC, one-class SVM, and nu-SVR"); + opt_svm_nu->guisection = _("SVM options"); + + opt_svm_p = G_define_option(); + opt_svm_p->key = "p"; + opt_svm_p->type = TYPE_DOUBLE; + opt_svm_p->key_desc = "value"; + opt_svm_p->required = NO; + opt_svm_p->answer = "0.1"; + opt_svm_p->description = + _("The epsilon in epsilon-insensitive loss function of epsilon-SVM regression"); + opt_svm_p->guisection = _("SVM options"); + + flag_svm_shrink = G_define_flag(); + flag_svm_shrink->key = 's'; + flag_svm_shrink->label = _("Do not use the shrinking heuristics"); + /* GTC: SVM flag description */ + flag_svm_shrink->description = + _("Defaults to use the shrinking heuristics"); + flag_svm_shrink->guisection = _("SVM options"); + + flag_svm_prob = G_define_flag(); + flag_svm_prob->key = 'p'; + flag_svm_prob->label = + _("Train a SVC or SVR model for probability estimates"); + /* GTC: SVM flag description */ + flag_svm_prob->description = _("Defaults to no probabilities in model"); + flag_svm_prob->guisection = _("SVM options"); + + + if (G_parser(argc, argv)) + exit(EXIT_FAILURE); + + /* Input validation */ + if (!I_find_group(opt_group->answer)) { + G_fatal_error(_("Group <%s> not found in current mapset"), + opt_group->answer); + } + if (opt_subgroup->answer && + !I_find_subgroup(opt_group->answer, opt_subgroup->answer)) { + G_fatal_error(_("Subgroup <%s> in group <%s> not found"), + opt_subgroup->answer, opt_group->answer); + } + /* TODO: Check signature file for overwrite */ + + /* TODO: Implement parameter checking duplicating svm_check_parameter() to generate translatable errors */ + parameters.cache_size = atoi(opt_svm_cache_size->answer); + parameters.degree = atoi(opt_svm_degree->answer); + parameters.gamma = atof(opt_svm_gamma->answer); + parameters.coef0 = atof(opt_svm_coef0->answer); + parameters.C = atof(opt_svm_cost->answer); + parameters.nu = atof(opt_svm_nu->answer); + parameters.p = atof(opt_svm_p->answer); + + if (strcmp(opt_svm_type->answer, "c_svc") == 0) + parameters.svm_type = C_SVC; + else if (strcmp(opt_svm_type->answer, "nu_svc") == 0) + parameters.svm_type = NU_SVC; + else if (strcmp(opt_svm_type->answer, "one_class") == 0) + parameters.svm_type = ONE_CLASS; + else if (strcmp(opt_svm_type->answer, "epsilon_svr") == 0) + parameters.svm_type = EPSILON_SVR; + else if (strcmp(opt_svm_type->answer, "nu_svr") == 0) + parameters.svm_type = NU_SVR; + else + G_fatal_error(_("Wrong SVM type")); + + if (strcmp(opt_svm_kernel->answer, "linear") == 0) + parameters.kernel_type = LINEAR; + else if (strcmp(opt_svm_kernel->answer, "poly") == 0) + parameters.kernel_type = POLY; + else if (strcmp(opt_svm_kernel->answer, "rbf") == 0) + parameters.kernel_type = RBF; + else if (strcmp(opt_svm_kernel->answer, "sigmoid") == 0) + parameters.kernel_type = SIGMOID; + else if (strcmp(opt_svm_kernel->answer, "precomputed") == 0) + parameters.kernel_type = PRECOMPUTED; + else + G_fatal_error(_("Wrong kernel type")); + + if (opt_svm_eps->answer) + parameters.eps = atof(opt_svm_eps->answer); + else { + if (parameters.svm_type == NU_SVC) + parameters.eps = 0.00001; + else + parameters.eps = 0.001; + } + + if (flag_svm_shrink->answer) + parameters.shrinking = 1; + else + parameters.shrinking = 0; + + if (flag_svm_prob->answer) + parameters.probability = 1; + else + parameters.probability = 0; + + /* TODO: implement weight support */ + parameters.nr_weight = 0; + + //parameters_error = svm_check_parameter(, ¶meters); + if (parameters_error) + G_fatal_error(_("SVM parameter validation returned an error: %s\n"), + parameters_error); + + /* Get bands */ + if (opt_subgroup->answer) { + if (!I_get_subgroup_ref + (opt_group->answer, opt_subgroup->answer, &bands)) { + G_fatal_error(_("There was an error reading subgroup <%s> in group <%s>"), + opt_subgroup->answer, opt_group->answer); + } + } + else { + if (!I_get_group_ref(opt_group->answer, &bands)) { + G_fatal_error(_("There was an error reading group <%s>"), + opt_group->answer); + } + } + if (bands.nfiles <= 0) { + if (opt_subgroup->answer) + G_fatal_error(_("Subgroup <%s> in group <%s> contains no raster maps."), + opt_subgroup->answer, opt_group->answer); + else + G_fatal_error(_("Group <%s> contains no raster maps."), + opt_group->answer); + } + + + exit(EXIT_SUCCESS); +} From 0ab6d44a67aa132b457ab7dcca9e06482bcf1c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Tue, 19 Jan 2021 20:11:33 +0200 Subject: [PATCH 004/123] i.svm: Add LIBSVM to configure system --- configure.in | 25 +++++++++++++++++++++++++ include/Make/Platform.make.in | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/configure.in b/configure.in index d85b4751340..951b347089b 100644 --- a/configure.in +++ b/configure.in @@ -283,6 +283,7 @@ LOC_ARG_WITH(odbc, ODBC, no) LOC_ARG_WITH(fftw, FFTW) LOC_ARG_WITH(blas, BLAS, no) LOC_ARG_WITH(lapack, LAPACK, no) +LOC_ARG_WITH(libsvm, LIBSVM, no) LOC_ARG_WITH(cairo, Cairo) LOC_ARG_WITH(freetype, FreeType) LOC_ARG_WITH(nls, NLS, no) @@ -381,6 +382,9 @@ LOC_ARG_WITH_LIB(blas, BLAS) LOC_ARG_WITH_INC(lapack, LAPACK) LOC_ARG_WITH_LIB(lapack, LAPACK) +LOC_ARG_WITH_INC(libsvm, LIBSVM) +LOC_ARG_WITH_LIB(libsvm, LIBSVM) + LOC_ARG_WITH_INC(cairo, cairo) LOC_ARG_WITH_LIB(cairo, cairo) LOC_ARG_WITH_LDFLAGS(cairo, cairo) @@ -1674,6 +1678,26 @@ AC_SUBST(LAPACKINC) # Done checking LAPACK +# LIBSVM option +LIBSVM_INC= +LIBSVM_LIB= +USE_LIBSVM= + +LOC_CHECK_USE(libsvm,LIBSVM,USE_LIBSVM) + +if test -n "$USE_LIBSVM"; then + LOC_CHECK_INC_PATH(libsvm,LIBSVM,LIBSVM_INC) + LOC_CHECK_INCLUDES(libsvm/svm.h,LIBSVM,$LIBSVM_INC) + LOC_CHECK_LIB_PATH(libsvm,LIBSVM,LIBSVM_LIB) + LOC_CHECK_LIBS(svm,svm_load_model,LIBSVM,$LIBSVM_LIB,LIBSVM_LIB,,,) + AC_DEFINE(HAVE_LIBSVM) +fi + +AC_SUBST(LIBSVM_INC) +AC_SUBST(LIBSVM_LIB) +AC_SUBST(USE_LIBSVM) +# Done with LIBSVM + # Enable Cairo display driver option LOC_CHECK_USE(cairo,Cairo,USE_CAIRO) @@ -2030,6 +2054,7 @@ LOC_MSG_USE(GEOS support,USE_GEOS) LOC_MSG_USE(LAPACK support,USE_LAPACK) LOC_MSG_USE(Large File support (LFS), USE_LARGEFILES) LOC_MSG_USE(libLAS support,USE_LIBLAS) +LOC_MSG_USE(LIBSVM support,USE_LIBSVM) LOC_MSG_USE(MySQL support,USE_MYSQL) LOC_MSG_USE(NetCDF support,USE_NETCDF) LOC_MSG_USE(NLS support,USE_NLS) diff --git a/include/Make/Platform.make.in b/include/Make/Platform.make.in index 710e9ee4151..6a780756d85 100644 --- a/include/Make/Platform.make.in +++ b/include/Make/Platform.make.in @@ -161,6 +161,11 @@ BLASINC = @BLASINC@ LAPACKLIB = @LAPACKLIB@ LAPACKINC = @LAPACKINC@ +#LIBSVM +LIBSVM_LIB = @LIBSVM_LIB@ +LIBSVM_INC = @LIBSVM_INC@ +USE_LIBSVM = @USE_LIBSVM@ + #GDAL/OGR GDALLIBS = @GDAL_LIBS@ GDALCFLAGS = @GDAL_CFLAGS@ From eb5baddc2861a55c05a4134750528bb159a19842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Tue, 19 Jan 2021 20:13:04 +0200 Subject: [PATCH 005/123] i.svm: Training implementation --- imagery/i.svm.train/Makefile | 6 +- imagery/i.svm.train/fill.c | 92 ++++++++++++++++++++++++++ imagery/i.svm.train/fill.h | 23 +++++++ imagery/i.svm.train/main.c | 123 +++++++++++++++++++++++++++-------- 4 files changed, 215 insertions(+), 29 deletions(-) create mode 100644 imagery/i.svm.train/fill.c create mode 100644 imagery/i.svm.train/fill.h diff --git a/imagery/i.svm.train/Makefile b/imagery/i.svm.train/Makefile index a7828026b23..19883b46eca 100644 --- a/imagery/i.svm.train/Makefile +++ b/imagery/i.svm.train/Makefile @@ -2,9 +2,13 @@ MODULE_TOPDIR = ../.. PGM = i.svm.train -LIBES = $(RASTERLIB) $(IMAGERYLIB) $(GISLIB) +LIBES = $(RASTERLIB) $(IMAGERYLIB) $(GISLIB) $(LIBSVM_LIB) DEPENDENCIES = $(RASTERDEP) $(IMAGERYDEP) $(GISDEP) +EXTRA_INC = $(LIBSVM_INC) + include $(MODULE_TOPDIR)/include/Make/Module.make +ifneq ($(USE_LIBSVM),) default: cmd +endif diff --git a/imagery/i.svm.train/fill.c b/imagery/i.svm.train/fill.c new file mode 100644 index 00000000000..6f1edb89446 --- /dev/null +++ b/imagery/i.svm.train/fill.c @@ -0,0 +1,92 @@ +/* + * i.svm.train Functions filling svm_problem struct + * + * Copyright 2020 by Maris Nartiss, and The GRASS Development Team + * Author: Maris Nartiss + * + * This program is free software licensed under the GPL (>=v2). + * Read the COPYING file that comes with GRASS for details. + * + */ +#include + +#include "fill.h" + + +void fill_problem(const char *name_labels, const char *mapset_labels, struct Ref band_refs, const char *mapset_group, struct svm_problem *problem) { + int label_num, label_max; + int value_num, value_max; + int row, col, band; + int nrows, ncols; + + int fd_labels; + DCELL *buf_labels; + + int *fd_bands; + DCELL **buf_bands; + + /* Keep track of used svm_problem node head */ + label_num = 0; + label_max = 0; + problem->l = 0; + problem->x = NULL; + problem->y = NULL; + + nrows = Rast_window_rows(); + ncols = Rast_window_cols(); + + fd_labels = Rast_open_old(name_labels, mapset_labels); + /* svm_problem always stores labels as doubles */ + buf_labels = Rast_allocate_d_buf(); + + buf_bands = (DCELL **) G_malloc(band_refs.nfiles * sizeof(DCELL *)); + fd_bands = (int *)G_calloc(band_refs.nfiles, sizeof(int)); + for (band = 0; band < band_refs.nfiles; band++) { + buf_bands[band] = Rast_allocate_d_buf(); + fd_bands[band] = Rast_open_old(band_refs.file[band].name, band_refs.file[band].mapset); + } + + + for (row = 0; row < nrows; row++) { + Rast_get_d_row(fd_labels, buf_labels, row); + for (band = 0; band < band_refs.nfiles; band++) + Rast_get_d_row(fd_bands[band], &buf_bands[band][0], row); + for (col = 0; col < ncols; col++) { + if (Rast_is_d_null_value(&buf_labels[col])) + continue; + if (label_num >= label_max) { + label_max += SIZE_INCREMENT; + problem->y = G_realloc(problem->y, + (size_t)label_max * sizeof(double)); + problem->x = G_realloc(problem->x, (size_t)label_max * sizeof(struct svm_node *)); + } + problem->l = label_num; + problem->y[label_num] = buf_labels[col]; + problem->x[label_num] = NULL; + value_num = 0; + value_max = 0; + for (band = 0; band < band_refs.nfiles; band++) { + if (Rast_is_d_null_value(&buf_bands[band][col])) + continue; + if (value_num >= value_max) { + /* Three bands are typical, thus we need 4 nodes */ + value_max += 4; + problem->x[label_num] = G_realloc(problem->x[label_num], + ((size_t)value_max + 1) * sizeof(struct svm_node)); + } + problem->x[label_num][value_num].index = band; + problem->x[label_num][value_num].value = buf_bands[band][col]; + value_num++; + } + /* If label has no data */ + if (value_num == 0) { + continue; + } + problem->x[label_num][value_num].index = -1; + label_num++; + } + } + + /* Although there could be more memory allocated, not all might be filled */ + problem->l = label_num; +} diff --git a/imagery/i.svm.train/fill.h b/imagery/i.svm.train/fill.h new file mode 100644 index 00000000000..634f6983694 --- /dev/null +++ b/imagery/i.svm.train/fill.h @@ -0,0 +1,23 @@ +/* + * i.svm.train Functions filling svm_problem struct + * + * Copyright 2020 by Maris Nartiss, and The GRASS Development Team + * Author: Maris Nartiss + * + * This program is free software licensed under the GPL (>=v2). + * Read the COPYING file that comes with GRASS for details. + * + */ + +#include + +#include + +#ifndef FILL_H +#define FILL_H + +#define SIZE_INCREMENT 64; + +void fill_problem(const char *, const char *, struct Ref, const char *, struct svm_problem *); + +#endif // FILL_H diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index df4b9344997..3ed2af95de4 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -22,20 +22,39 @@ #include #include +#include "fill.h" + +/* LIBSVM message wrapper */ +void print_func(const char *s) { + G_verbose_message("SVMLIB: %s", s); +}; + int main(int argc, char *argv[]) { struct GModule *module; - struct Option *opt_group, *opt_subgroup, *opt_sigfile; + struct Option *opt_group, *opt_subgroup, *opt_sigfile, *opt_labels; struct Option *opt_svm_type, *opt_svm_kernel; struct Option *opt_svm_cache_size, *opt_svm_degree, *opt_svm_gamma, *opt_svm_coef0, *opt_svm_eps, *opt_svm_cost, *opt_svm_nu, *opt_svm_p; struct Flag *flag_svm_shrink, *flag_svm_prob; - struct Ref bands; + const char *mapset_labels; + char name_labels[GNAME_MAX], name_group[GNAME_MAX], name_subgroup[GNAME_MAX]; + char mapset_group[GMAPSET_MAX], mapset_subgroup[GMAPSET_MAX]; + char element[GPATH_MAX], model_file[GPATH_MAX]; + + struct Ref band_ref; struct svm_parameter parameters; const char *parameters_error; + + struct svm_problem problem; + + struct svm_model *model; + int out_status; + + G_gisinit(argv[0]); @@ -47,18 +66,23 @@ int main(int argc, char *argv[]) module->description = _("Train SVM"); opt_group = G_define_standard_option(G_OPT_I_GROUP); + /* GTC: SVM training input */ + opt_group->description = _("Maps with feature values (attributes)"); opt_subgroup = G_define_standard_option(G_OPT_I_SUBGROUP); opt_subgroup->required = NO; + + opt_labels = G_define_standard_option(G_OPT_R_INPUTS); + opt_labels->description = _("Map with training labels or target values"); opt_sigfile = G_define_option(); - opt_sigfile->key = "signaturefile"; + opt_sigfile->key = "model"; opt_sigfile->type = TYPE_STRING; opt_sigfile->key_desc = "name"; opt_sigfile->required = YES; - opt_sigfile->gisprompt = "new,sig,sigfile"; + opt_sigfile->gisprompt = "new,svm,sigfile"; opt_sigfile->description = - _("Name for output file containing result signatures"); + _("Name for output file containing trained model"); opt_svm_type = G_define_option(); opt_svm_type->key = "type"; @@ -208,17 +232,37 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); /* Input validation */ - if (!I_find_group(opt_group->answer)) { - G_fatal_error(_("Group <%s> not found in current mapset"), - opt_group->answer); + /* Input maps */ + if (G_unqualified_name(opt_group->answer, NULL, name_group, mapset_group) == 0) + strcpy(mapset_group, G_mapset()); + if (opt_subgroup->answer && + G_unqualified_name(opt_subgroup->answer, NULL, name_subgroup, mapset_subgroup) != 0 && + strcmp(mapset_subgroup, mapset_group) != 0) + G_fatal_error(_("Invalid subgroup <%s> provided"), opt_subgroup->answer); + if (!I_find_group2(name_group, mapset_group)) { + G_fatal_error(_("Group <%s> not found in mapset <%s>"), + name_group, mapset_group); } if (opt_subgroup->answer && - !I_find_subgroup(opt_group->answer, opt_subgroup->answer)) { - G_fatal_error(_("Subgroup <%s> in group <%s> not found"), - opt_subgroup->answer, opt_group->answer); + !I_find_subgroup2(name_group, name_subgroup, mapset_group)) { + G_fatal_error(_("Subgroup <%s> in group <%s@%s> not found"), + name_subgroup, name_group, mapset_group); + } + + strcpy(name_labels, opt_labels->answer); + if ((mapset_labels = G_find_raster(name_labels, "")) == NULL) { + G_fatal_error(_("Raster map <%s> not found"), opt_labels->answer); } - /* TODO: Check signature file for overwrite */ + + if (opt_subgroup->answer) + sprintf(element, "subgroup%c%s%csvm%c%s", HOST_DIRSEP, name_subgroup, HOST_DIRSEP, HOST_DIRSEP, opt_sigfile->answer); + else + sprintf(element, "svm%c%s", HOST_DIRSEP, opt_sigfile->answer); + if (!G_get_overwrite() && G_find_file2_misc("group", element, name_group, G_mapset()) != NULL) + G_fatal_error(_("option <%s>: <%s> exists. To overwrite, use the --overwrite flag"), + opt_sigfile->key, opt_sigfile->answer); + /* Input SVM parameters */ /* TODO: Implement parameter checking duplicating svm_check_parameter() to generate translatable errors */ parameters.cache_size = atoi(opt_svm_cache_size->answer); parameters.degree = atoi(opt_svm_degree->answer); @@ -276,34 +320,57 @@ int main(int argc, char *argv[]) /* TODO: implement weight support */ parameters.nr_weight = 0; - //parameters_error = svm_check_parameter(, ¶meters); - if (parameters_error) - G_fatal_error(_("SVM parameter validation returned an error: %s\n"), - parameters_error); /* Get bands */ if (opt_subgroup->answer) { - if (!I_get_subgroup_ref - (opt_group->answer, opt_subgroup->answer, &bands)) { - G_fatal_error(_("There was an error reading subgroup <%s> in group <%s>"), - opt_subgroup->answer, opt_group->answer); + if (!I_get_subgroup_ref2 + (name_group, opt_subgroup->answer, mapset_group, &band_ref)) { + G_fatal_error(_("There was an error reading subgroup <%s> in group <%s@%s>"), + opt_subgroup->answer, name_group, mapset_group); } } else { - if (!I_get_group_ref(opt_group->answer, &bands)) { - G_fatal_error(_("There was an error reading group <%s>"), - opt_group->answer); + if (!I_get_group_ref2(name_group, mapset_group, &band_ref)) { + G_fatal_error(_("There was an error reading group <%s@%s>"), + name_group, mapset_group); } } - if (bands.nfiles <= 0) { + if (band_ref.nfiles <= 0) { if (opt_subgroup->answer) - G_fatal_error(_("Subgroup <%s> in group <%s> contains no raster maps."), - opt_subgroup->answer, opt_group->answer); + G_fatal_error(_("Subgroup <%s> in group <%s@%s> contains no raster maps."), + opt_subgroup->answer, name_group, mapset_group); else - G_fatal_error(_("Group <%s> contains no raster maps."), - opt_group->answer); + G_fatal_error(_("Group <%s@%s> contains no raster maps."), + name_group, mapset_group); } + + svm_set_print_string_function(&print_func); + + /* Fill svm_problem struct with training data */ + fill_problem(name_labels, mapset_labels, band_ref, mapset_group, &problem); + + /* svm_check_parameter needs filled svm_problem struct thus checking only now */ + parameters_error = svm_check_parameter(&problem, ¶meters); + if (parameters_error) + G_fatal_error(_("SVM parameter validation returned an error: %s\n"), + parameters_error); + /* Train model */ + model = svm_train(&problem, ¶meters); + /* Write out training results */ + /* TODO: Move to Imagery library? */ + if (opt_subgroup->answer) + sprintf(element, "group%c%s%csubgroup%c%s%csvm", HOST_DIRSEP, name_group, HOST_DIRSEP, HOST_DIRSEP, opt_subgroup->answer, HOST_DIRSEP); + else + sprintf(element, "group%c%s%csvm", HOST_DIRSEP, name_group, HOST_DIRSEP); + if (G_make_mapset_element(element) == 0) + G_fatal_error(_("Failed to create signatures for group <%s>"), opt_group->answer); + G_file_name_misc(model_file, NULL, element, opt_sigfile->answer, G_mapset()); + out_status = svm_save_model(model_file, model); + if (out_status != 0) { + G_fatal_error(_("Unable to write trained model to file '%s'. Error code: %d"), model_file, out_status); + } + G_message(_("Training successfuly complete")); exit(EXIT_SUCCESS); } From f46610e216cbea6aef13a605d879bbc18731df32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Thu, 28 Jan 2021 22:18:26 +0200 Subject: [PATCH 006/123] i.svm.train: Clean up on exit --- imagery/i.svm.train/fill.c | 47 ++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/imagery/i.svm.train/fill.c b/imagery/i.svm.train/fill.c index 6f1edb89446..01dd2365e88 100644 --- a/imagery/i.svm.train/fill.c +++ b/imagery/i.svm.train/fill.c @@ -13,40 +13,45 @@ #include "fill.h" -void fill_problem(const char *name_labels, const char *mapset_labels, struct Ref band_refs, const char *mapset_group, struct svm_problem *problem) { +void fill_problem(const char *name_labels, const char *mapset_labels, + struct Ref band_refs, const char *mapset_group, + struct svm_problem *problem) +{ int label_num, label_max; int value_num, value_max; int row, col, band; int nrows, ncols; - + int fd_labels; DCELL *buf_labels; - + int *fd_bands; DCELL **buf_bands; - + /* Keep track of used svm_problem node head */ label_num = 0; label_max = 0; problem->l = 0; problem->x = NULL; problem->y = NULL; - + nrows = Rast_window_rows(); ncols = Rast_window_cols(); - + fd_labels = Rast_open_old(name_labels, mapset_labels); /* svm_problem always stores labels as doubles */ buf_labels = Rast_allocate_d_buf(); - + buf_bands = (DCELL **) G_malloc(band_refs.nfiles * sizeof(DCELL *)); fd_bands = (int *)G_calloc(band_refs.nfiles, sizeof(int)); for (band = 0; band < band_refs.nfiles; band++) { buf_bands[band] = Rast_allocate_d_buf(); - fd_bands[band] = Rast_open_old(band_refs.file[band].name, band_refs.file[band].mapset); + fd_bands[band] = + Rast_open_old(band_refs.file[band].name, + band_refs.file[band].mapset); } - - + + for (row = 0; row < nrows; row++) { Rast_get_d_row(fd_labels, buf_labels, row); for (band = 0; band < band_refs.nfiles; band++) @@ -57,8 +62,10 @@ void fill_problem(const char *name_labels, const char *mapset_labels, struct Ref if (label_num >= label_max) { label_max += SIZE_INCREMENT; problem->y = G_realloc(problem->y, - (size_t)label_max * sizeof(double)); - problem->x = G_realloc(problem->x, (size_t)label_max * sizeof(struct svm_node *)); + (size_t)label_max * sizeof(double)); + problem->x = + G_realloc(problem->x, + (size_t)label_max * sizeof(struct svm_node *)); } problem->l = label_num; problem->y[label_num] = buf_labels[col]; @@ -72,7 +79,10 @@ void fill_problem(const char *name_labels, const char *mapset_labels, struct Ref /* Three bands are typical, thus we need 4 nodes */ value_max += 4; problem->x[label_num] = G_realloc(problem->x[label_num], - ((size_t)value_max + 1) * sizeof(struct svm_node)); + ((size_t)value_max + + 1) * + sizeof(struct + svm_node)); } problem->x[label_num][value_num].index = band; problem->x[label_num][value_num].value = buf_bands[band][col]; @@ -86,7 +96,16 @@ void fill_problem(const char *name_labels, const char *mapset_labels, struct Ref label_num++; } } - + /* Although there could be more memory allocated, not all might be filled */ problem->l = label_num; + + /* Clean up */ + Rast_close(fd_labels); + G_free(buf_labels); + + for (band = 0; band < band_refs.nfiles; band++) { + Rast_close(fd_bands[band]); + G_free(buf_bands[band]); + } } From 74bd39494ea0fb3101f051be2c93a7578c8cf156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Thu, 28 Jan 2021 22:19:42 +0200 Subject: [PATCH 007/123] i.svm.predict: First version of value predicting with SVM --- imagery/i.svm.predict/Makefile | 14 ++ imagery/i.svm.predict/main.c | 266 +++++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 imagery/i.svm.predict/Makefile create mode 100644 imagery/i.svm.predict/main.c diff --git a/imagery/i.svm.predict/Makefile b/imagery/i.svm.predict/Makefile new file mode 100644 index 00000000000..d20b31a3cbe --- /dev/null +++ b/imagery/i.svm.predict/Makefile @@ -0,0 +1,14 @@ +MODULE_TOPDIR = ../.. + +PGM = i.svm.predict + +LIBES = $(RASTERLIB) $(IMAGERYLIB) $(GISLIB) $(LIBSVM_LIB) +DEPENDENCIES = $(RASTERDEP) $(IMAGERYDEP) $(GISDEP) + +EXTRA_INC = $(LIBSVM_INC) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +ifneq ($(USE_LIBSVM),) +default: cmd +endif diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c new file mode 100644 index 00000000000..09a631c7b81 --- /dev/null +++ b/imagery/i.svm.predict/main.c @@ -0,0 +1,266 @@ + +/**************************************************************************** + * + * MODULE: i.svm.predict + * AUTHOR(S): Maris Nartiss - maris.gis gmail.com + * PURPOSE: Predicts values with Support Vector Machine classifier + * + * COPYRIGHT: (C) 2020 by Maris Nartiss and the GRASS Development Team + * + * This program is free software under the GNU General Public + * License (>=v2). Read the file COPYING that comes with GRASS + * for details. + * + *****************************************************************************/ +#include +#include + +#include + +#include +#include +#include +#include + +#include "fill.h" + +/* LIBSVM message wrapper */ +void print_func(const char *s) +{ + G_verbose_message("%s", s); +}; + + +int main(int argc, char *argv[]) +{ + struct GModule *module; + struct Option *opt_group, *opt_subgroup, *opt_sigfile, *opt_values; + struct Option *opt_svm_cache_size; + + char name_values[GNAME_MAX], name_group[GNAME_MAX], + name_subgroup[GNAME_MAX]; + const char *mapset_model; + char mapset_values[GMAPSET_MAX], mapset_group[GMAPSET_MAX], + mapset_subgroup[GMAPSET_MAX]; + char element[GPATH_MAX], model_file[GPATH_MAX]; + + struct Ref band_ref; + + struct svm_model *model; + + G_gisinit(argv[0]); + + module = G_define_module(); + G_add_keyword(_("imagery")); + G_add_keyword(_("svm")); + G_add_keyword(_("classification")); + G_add_keyword(_("prediction")); + G_add_keyword(_("regression")); + module->description = _("Predict with SVM"); + + opt_group = G_define_standard_option(G_OPT_I_GROUP); + /* GTC: SVM prediction input */ + opt_group->description = _("Maps with feature values (attributes)"); + + opt_subgroup = G_define_standard_option(G_OPT_I_SUBGROUP); + opt_subgroup->required = NO; + + opt_sigfile = G_define_option(); + opt_sigfile->key = "model"; + opt_sigfile->type = TYPE_STRING; + opt_sigfile->key_desc = "name"; + opt_sigfile->required = YES; + opt_sigfile->gisprompt = "old,svm,sigfile"; + opt_sigfile->description = _("Name trained SVM model"); + + opt_values = G_define_standard_option(G_OPT_R_OUTPUT); + opt_values->required = YES; + opt_values->description = + _("Output map with predicted class / calculated value"); + + opt_svm_cache_size = G_define_option(); + opt_svm_cache_size->key = "cache"; + opt_svm_cache_size->type = TYPE_INTEGER; + opt_svm_cache_size->key_desc = "cache size"; + opt_svm_cache_size->required = NO; + opt_svm_cache_size->options = "1-999999999"; + opt_svm_cache_size->answer = "512"; + opt_svm_cache_size->description = _("Kernel cache size in MB"); + /* opt_svm_cache_size->guisection = _("SVM options"); */ + + + if (G_parser(argc, argv)) + exit(EXIT_FAILURE); + + /* Input validation */ + /* Input maps */ + if (G_unqualified_name(opt_group->answer, NULL, name_group, mapset_group) + == 0) + strcpy(mapset_group, G_mapset()); + if (opt_subgroup->answer && + G_unqualified_name(opt_subgroup->answer, NULL, name_subgroup, + mapset_subgroup) != 0 && + strcmp(mapset_subgroup, mapset_group) != 0) + G_fatal_error(_("Invalid subgroup <%s> provided"), + opt_subgroup->answer); + if (!I_find_group2(name_group, mapset_group)) { + G_fatal_error(_("Group <%s> not found in mapset <%s>"), + name_group, mapset_group); + } + if (opt_subgroup->answer && + !I_find_subgroup2(name_group, name_subgroup, mapset_group)) { + G_fatal_error(_("Subgroup <%s> in group <%s@%s> not found"), + name_subgroup, name_group, mapset_group); + } + + if (opt_subgroup->answer) + sprintf(element, "subgroup%c%s%csvm%c%s", HOST_DIRSEP, name_subgroup, + HOST_DIRSEP, HOST_DIRSEP, opt_sigfile->answer); + else + sprintf(element, "svm%c%s", HOST_DIRSEP, opt_sigfile->answer); + mapset_model = G_find_file2_misc("group", element, name_group, ""); + if (mapset_model == NULL) + G_fatal_error(_("File <%s> with trained SVM model not found"), + opt_sigfile->answer); + + if (G_unqualified_name + (opt_values->answer, G_mapset(), name_values, mapset_values) < 0) + G_fatal_error(_("<%s> does not match the current mapset"), + mapset_values); + if (G_legal_filename(name_values) < 0) + G_fatal_error(_("<%s> is an illegal file name"), name_values); + + /* Get bands */ + if (opt_subgroup->answer) { + if (!I_get_subgroup_ref2 + (name_group, opt_subgroup->answer, mapset_group, &band_ref)) { + G_fatal_error(_("There was an error reading subgroup <%s> in group <%s@%s>"), + opt_subgroup->answer, name_group, mapset_group); + } + } + else { + if (!I_get_group_ref2(name_group, mapset_group, &band_ref)) { + G_fatal_error(_("There was an error reading group <%s@%s>"), + name_group, mapset_group); + } + } + if (band_ref.nfiles <= 0) { + if (opt_subgroup->answer) + G_fatal_error(_("Subgroup <%s> in group <%s@%s> contains no raster maps."), + opt_subgroup->answer, name_group, mapset_group); + else + G_fatal_error(_("Group <%s@%s> contains no raster maps."), + name_group, mapset_group); + } + + svm_set_print_string_function(&print_func); + + /* Load trained model from a file */ + /* TODO: move to imagery lib? */ + if (opt_subgroup->answer) + sprintf(element, "group%c%s%csubgroup%c%s%csvm", HOST_DIRSEP, + name_group, HOST_DIRSEP, HOST_DIRSEP, opt_subgroup->answer, + HOST_DIRSEP); + else + sprintf(element, "group%c%s%csvm", HOST_DIRSEP, name_group, + HOST_DIRSEP); + G_file_name_misc(model_file, NULL, element, opt_sigfile->answer, + mapset_model); + model = svm_load_model(model_file); + if (model == NULL) + G_fatal_error(_("Unable to open trained model file <%s>"), + opt_sigfile->answer); + + /* For row, cell: svm_predict */ + int row, col, band; + int nrows, ncols; + int svm_type; + int fd_values = 0; + RASTER_MAP_TYPE out_type; + + int *fd_bands; + DCELL **buf_bands; + struct svm_node *nodes; + + svm_type = svm_get_svm_type(model); + + nrows = Rast_window_rows(); + ncols = Rast_window_cols(); + + buf_bands = (DCELL **) G_malloc(band_ref.nfiles * sizeof(DCELL *)); + fd_bands = (int *)G_calloc(band_ref.nfiles, sizeof(int)); + for (band = 0; band < band_ref.nfiles; band++) { + buf_bands[band] = Rast_allocate_d_buf(); + fd_bands[band] = + Rast_open_old(band_ref.file[band].name, + band_ref.file[band].mapset); + } + nodes = + (struct svm_node *)G_malloc(((size_t)band_ref.nfiles + 1) * + sizeof(struct svm_node)); + + /* Predict a class or calculate a value */ + if (svm_type == C_SVC || svm_type == NU_SVC || svm_type == ONE_CLASS) { + CELL *out_row; + DCELL val; + + out_row = Rast_allocate_c_buf(); + out_type = CELL_TYPE; + fd_values = Rast_open_c_new(name_values); + + for (row = 0; row < nrows; row++) { + G_percent(row, nrows, 2); + for (band = 0; band < band_ref.nfiles; band++) + Rast_get_d_row(fd_bands[band], &buf_bands[band][0], row); + for (col = 0; col < ncols; col++) { + nodes[0].index = -1; + for (band = 0; band < band_ref.nfiles; band++) { + if (Rast_is_d_null_value(&buf_bands[band][col])) + continue; + nodes[band].index = band; + nodes[band].value = buf_bands[band][col]; + } + + /* All values where NULLs */ + if (nodes[0].index == -1) { + Rast_set_c_null_value(&out_row[col], 1); + continue; + } + /* + for (band = 0; band < (band_ref.nfiles + 1); band++) { + if (nodes[band].index = -1) + continue; + printf("push[%d][%d][%d]=%f ", row, col, band, nodes[band].value); + } + * */ + val = svm_predict(model, nodes); + out_row[col] = (CELL) val; + //printf(" => %f\n", val); + } + Rast_put_row(fd_values, out_row, out_type); + } + G_percent(nrows, nrows, 2); + } + else { + /* + DCELL *out_row; + out_row = Rast_allocate_d_buf(); + out_type = DCELL_TYPE; + fd_values = Rast_open_d_new(name_values); + */ + } + + /* TODO: + * CATs + * History + */ + + /* Clean up */ + Rast_close(fd_values); + for (band = 0; band < band_ref.nfiles; band++) { + Rast_close(fd_bands[band]); + G_free(buf_bands[band]); + } + + exit(EXIT_SUCCESS); +} From 822615f3b2019440020b0fd6cef44d1f0f5593b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Sun, 31 Jan 2021 18:05:45 +0200 Subject: [PATCH 008/123] i.svm: Implement history tracking and category label preservation --- imagery/i.svm.predict/main.c | 136 ++++++++++++++++++++++++----------- imagery/i.svm.train/fill.c | 3 + imagery/i.svm.train/fill.h | 3 +- imagery/i.svm.train/main.c | 113 +++++++++++++++++++---------- 4 files changed, 175 insertions(+), 80 deletions(-) diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c index 09a631c7b81..e6ffb15a032 100644 --- a/imagery/i.svm.predict/main.c +++ b/imagery/i.svm.predict/main.c @@ -22,7 +22,6 @@ #include #include -#include "fill.h" /* LIBSVM message wrapper */ void print_func(const char *s) @@ -39,15 +38,20 @@ int main(int argc, char *argv[]) char name_values[GNAME_MAX], name_group[GNAME_MAX], name_subgroup[GNAME_MAX]; - const char *mapset_model; - char mapset_values[GMAPSET_MAX], mapset_group[GMAPSET_MAX], - mapset_subgroup[GMAPSET_MAX]; - char element[GPATH_MAX], model_file[GPATH_MAX]; + const char *name_sigfile, *mapset_sigfile; + char mapset_group[GMAPSET_MAX], mapset_subgroup[GMAPSET_MAX], + mapset_values[GMAPSET_MAX]; + char sigfile_dir[GPATH_MAX], model_file[GPATH_MAX]; + char cats_path[GPATH_MAX], cats_file[GPATH_MAX]; struct Ref band_ref; struct svm_model *model; + struct History history; + FILE *hist_file; + char hist_line[4096]; /* history lines are limited to 4096 */ + G_gisinit(argv[0]); module = G_define_module(); @@ -70,7 +74,7 @@ int main(int argc, char *argv[]) opt_sigfile->type = TYPE_STRING; opt_sigfile->key_desc = "name"; opt_sigfile->required = YES; - opt_sigfile->gisprompt = "old,svm,sigfile"; + opt_sigfile->gisprompt = "old,rsvm,sigfile"; opt_sigfile->description = _("Name trained SVM model"); opt_values = G_define_standard_option(G_OPT_R_OUTPUT); @@ -113,15 +117,19 @@ int main(int argc, char *argv[]) name_subgroup, name_group, mapset_group); } + name_sigfile = opt_sigfile->answer; if (opt_subgroup->answer) - sprintf(element, "subgroup%c%s%csvm%c%s", HOST_DIRSEP, name_subgroup, - HOST_DIRSEP, HOST_DIRSEP, opt_sigfile->answer); + sprintf(sigfile_dir, "group%c%s%csubgroup%c%s%crsvm", HOST_DIRSEP, + name_group, HOST_DIRSEP, HOST_DIRSEP, opt_subgroup->answer, + HOST_DIRSEP); else - sprintf(element, "svm%c%s", HOST_DIRSEP, opt_sigfile->answer); - mapset_model = G_find_file2_misc("group", element, name_group, ""); - if (mapset_model == NULL) + sprintf(sigfile_dir, "group%c%s%crsvm", HOST_DIRSEP, name_group, + HOST_DIRSEP); + mapset_sigfile = + G_find_file2_misc(sigfile_dir, "model", name_sigfile, ""); + if (mapset_sigfile == NULL) G_fatal_error(_("File <%s> with trained SVM model not found"), - opt_sigfile->answer); + name_sigfile); if (G_unqualified_name (opt_values->answer, G_mapset(), name_values, mapset_values) < 0) @@ -156,21 +164,15 @@ int main(int argc, char *argv[]) svm_set_print_string_function(&print_func); /* Load trained model from a file */ - /* TODO: move to imagery lib? */ - if (opt_subgroup->answer) - sprintf(element, "group%c%s%csubgroup%c%s%csvm", HOST_DIRSEP, - name_group, HOST_DIRSEP, HOST_DIRSEP, opt_subgroup->answer, - HOST_DIRSEP); - else - sprintf(element, "group%c%s%csvm", HOST_DIRSEP, name_group, - HOST_DIRSEP); - G_file_name_misc(model_file, NULL, element, opt_sigfile->answer, - mapset_model); + G_verbose_message("Reading in trained SVM"); + G_file_name_misc(model_file, sigfile_dir, "model", name_sigfile, + mapset_sigfile); model = svm_load_model(model_file); if (model == NULL) G_fatal_error(_("Unable to open trained model file <%s>"), - opt_sigfile->answer); + name_sigfile); + G_message(_("Starting value prediction process")); /* For row, cell: svm_predict */ int row, col, band; int nrows, ncols; @@ -226,34 +228,50 @@ int main(int argc, char *argv[]) Rast_set_c_null_value(&out_row[col], 1); continue; } - /* - for (band = 0; band < (band_ref.nfiles + 1); band++) { - if (nodes[band].index = -1) - continue; - printf("push[%d][%d][%d]=%f ", row, col, band, nodes[band].value); - } - * */ + val = svm_predict(model, nodes); out_row[col] = (CELL) val; - //printf(" => %f\n", val); } Rast_put_row(fd_values, out_row, out_type); } - G_percent(nrows, nrows, 2); + G_percent(1, 1, 1); + G_free(out_row); } else { - /* - DCELL *out_row; - out_row = Rast_allocate_d_buf(); - out_type = DCELL_TYPE; - fd_values = Rast_open_d_new(name_values); - */ - } + DCELL *out_row; + DCELL val; - /* TODO: - * CATs - * History - */ + out_row = Rast_allocate_d_buf(); + out_type = DCELL_TYPE; + fd_values = Rast_open_fp_new(name_values); + + for (row = 0; row < nrows; row++) { + G_percent(row, nrows, 2); + for (band = 0; band < band_ref.nfiles; band++) + Rast_get_d_row(fd_bands[band], &buf_bands[band][0], row); + for (col = 0; col < ncols; col++) { + nodes[0].index = -1; + for (band = 0; band < band_ref.nfiles; band++) { + if (Rast_is_d_null_value(&buf_bands[band][col])) + continue; + nodes[band].index = band; + nodes[band].value = buf_bands[band][col]; + } + + /* All values where NULLs */ + if (nodes[0].index == -1) { + Rast_set_d_null_value(&out_row[col], 1); + continue; + } + + val = svm_predict(model, nodes); + out_row[col] = val; + } + Rast_put_row(fd_values, out_row, out_type); + } + G_percent(1, 1, 1); + G_free(out_row); + } /* Clean up */ Rast_close(fd_values); @@ -261,6 +279,38 @@ int main(int argc, char *argv[]) Rast_close(fd_bands[band]); G_free(buf_bands[band]); } + G_free(nodes); + + /* Try to give full history */ + G_verbose_message("Writing out history"); + Rast_short_history(name_values, "raster", &history); + hist_file = + G_fopen_old_misc(sigfile_dir, "history", name_sigfile, + mapset_sigfile); + if (hist_file != NULL) { + if (G_getl(hist_line, sizeof(hist_line), hist_file)) + Rast_append_history(&history, hist_line); + fclose(hist_file); + } + Rast_command_history(&history); + if (opt_subgroup->answer) + Rast_format_history(&history, HIST_DATSRC_1, + "Group/subgroup: %s@%s/%s", name_group, + mapset_group, opt_subgroup->answer); + else + Rast_format_history(&history, HIST_DATSRC_1, "Group: %s@%s", + name_group, mapset_group); + Rast_format_history(&history, HIST_DATSRC_2, "Signature file: %s@%s", + name_sigfile, mapset_sigfile); + Rast_write_history(name_values, &history); + + /* Copy CATs file from the original training map */ + /* TODO: figure out if ONE_CLASS also needs original CATs */ + G_verbose_message("Copying category information"); + G_file_name_misc(cats_file, sigfile_dir, "cats", name_sigfile, + mapset_sigfile); + G_file_name(cats_path, "cats", name_values, G_mapset()); + G_copy_file(cats_file, cats_path); /* It's still OK if it fails here */ exit(EXIT_SUCCESS); } diff --git a/imagery/i.svm.train/fill.c b/imagery/i.svm.train/fill.c index 01dd2365e88..59d4de0f6c8 100644 --- a/imagery/i.svm.train/fill.c +++ b/imagery/i.svm.train/fill.c @@ -53,6 +53,7 @@ void fill_problem(const char *name_labels, const char *mapset_labels, for (row = 0; row < nrows; row++) { + G_percent(row, nrows, 10); Rast_get_d_row(fd_labels, buf_labels, row); for (band = 0; band < band_refs.nfiles; band++) Rast_get_d_row(fd_bands[band], &buf_bands[band][0], row); @@ -108,4 +109,6 @@ void fill_problem(const char *name_labels, const char *mapset_labels, Rast_close(fd_bands[band]); G_free(buf_bands[band]); } + G_percent(1, 1, 1); + G_percent_reset(); } diff --git a/imagery/i.svm.train/fill.h b/imagery/i.svm.train/fill.h index 634f6983694..51298172a0c 100644 --- a/imagery/i.svm.train/fill.h +++ b/imagery/i.svm.train/fill.h @@ -18,6 +18,7 @@ #define SIZE_INCREMENT 64; -void fill_problem(const char *, const char *, struct Ref, const char *, struct svm_problem *); +void fill_problem(const char *, const char *, struct Ref, const char *, + struct svm_problem *); #endif // FILL_H diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index 3ed2af95de4..9a8d5cce793 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -25,8 +25,9 @@ #include "fill.h" /* LIBSVM message wrapper */ -void print_func(const char *s) { - G_verbose_message("SVMLIB: %s", s); +void print_func(const char *s) +{ + G_verbose_message("%s", s); }; @@ -39,22 +40,26 @@ int main(int argc, char *argv[]) *opt_svm_coef0, *opt_svm_eps, *opt_svm_cost, *opt_svm_nu, *opt_svm_p; struct Flag *flag_svm_shrink, *flag_svm_prob; - const char *mapset_labels; - char name_labels[GNAME_MAX], name_group[GNAME_MAX], name_subgroup[GNAME_MAX]; + const char *mapset_labels, *name_sigfile; + char name_labels[GNAME_MAX], name_group[GNAME_MAX], + name_subgroup[GNAME_MAX]; char mapset_group[GMAPSET_MAX], mapset_subgroup[GMAPSET_MAX]; - char element[GPATH_MAX], model_file[GPATH_MAX]; - + char sigfile_dir[GPATH_MAX], out_file[GPATH_MAX]; + struct Ref band_ref; struct svm_parameter parameters; const char *parameters_error; - + struct svm_problem problem; - + struct svm_model *model; int out_status; - - + + struct Categories cats; + char cats_path[GPATH_MAX]; + FILE *hist_file; + char *cmdline; G_gisinit(argv[0]); @@ -71,7 +76,7 @@ int main(int argc, char *argv[]) opt_subgroup = G_define_standard_option(G_OPT_I_SUBGROUP); opt_subgroup->required = NO; - + opt_labels = G_define_standard_option(G_OPT_R_INPUTS); opt_labels->description = _("Map with training labels or target values"); @@ -80,7 +85,7 @@ int main(int argc, char *argv[]) opt_sigfile->type = TYPE_STRING; opt_sigfile->key_desc = "name"; opt_sigfile->required = YES; - opt_sigfile->gisprompt = "new,svm,sigfile"; + opt_sigfile->gisprompt = "new,rsvm,sigfile"; opt_sigfile->description = _("Name for output file containing trained model"); @@ -233,12 +238,15 @@ int main(int argc, char *argv[]) /* Input validation */ /* Input maps */ - if (G_unqualified_name(opt_group->answer, NULL, name_group, mapset_group) == 0) + if (G_unqualified_name(opt_group->answer, NULL, name_group, mapset_group) + == 0) strcpy(mapset_group, G_mapset()); if (opt_subgroup->answer && - G_unqualified_name(opt_subgroup->answer, NULL, name_subgroup, mapset_subgroup) != 0 && + G_unqualified_name(opt_subgroup->answer, NULL, name_subgroup, + mapset_subgroup) != 0 && strcmp(mapset_subgroup, mapset_group) != 0) - G_fatal_error(_("Invalid subgroup <%s> provided"), opt_subgroup->answer); + G_fatal_error(_("Invalid subgroup <%s> provided"), + opt_subgroup->answer); if (!I_find_group2(name_group, mapset_group)) { G_fatal_error(_("Group <%s> not found in mapset <%s>"), name_group, mapset_group); @@ -248,19 +256,25 @@ int main(int argc, char *argv[]) G_fatal_error(_("Subgroup <%s> in group <%s@%s> not found"), name_subgroup, name_group, mapset_group); } - + strcpy(name_labels, opt_labels->answer); if ((mapset_labels = G_find_raster(name_labels, "")) == NULL) { G_fatal_error(_("Raster map <%s> not found"), opt_labels->answer); } - + + name_sigfile = opt_sigfile->answer; if (opt_subgroup->answer) - sprintf(element, "subgroup%c%s%csvm%c%s", HOST_DIRSEP, name_subgroup, HOST_DIRSEP, HOST_DIRSEP, opt_sigfile->answer); + sprintf(sigfile_dir, "group%c%s%csubgroup%c%s%crsvm", HOST_DIRSEP, + name_group, HOST_DIRSEP, HOST_DIRSEP, opt_subgroup->answer, + HOST_DIRSEP); else - sprintf(element, "svm%c%s", HOST_DIRSEP, opt_sigfile->answer); - if (!G_get_overwrite() && G_find_file2_misc("group", element, name_group, G_mapset()) != NULL) - G_fatal_error(_("option <%s>: <%s> exists. To overwrite, use the --overwrite flag"), - opt_sigfile->key, opt_sigfile->answer); + sprintf(sigfile_dir, "group%c%s%crsvm", HOST_DIRSEP, name_group, + HOST_DIRSEP); + if (!G_get_overwrite() && + G_find_file2_misc(sigfile_dir, "model", name_sigfile, + G_mapset()) != NULL) + G_fatal_error(_("option <%s>: <%s> exists. To overwrite, use the --overwrite flag"), + opt_sigfile->key, name_sigfile); /* Input SVM parameters */ /* TODO: Implement parameter checking duplicating svm_check_parameter() to generate translatable errors */ @@ -320,7 +334,6 @@ int main(int argc, char *argv[]) /* TODO: implement weight support */ parameters.nr_weight = 0; - /* Get bands */ if (opt_subgroup->answer) { if (!I_get_subgroup_ref2 @@ -343,34 +356,62 @@ int main(int argc, char *argv[]) G_fatal_error(_("Group <%s@%s> contains no raster maps."), name_group, mapset_group); } - + svm_set_print_string_function(&print_func); /* Fill svm_problem struct with training data */ - fill_problem(name_labels, mapset_labels, band_ref, mapset_group, &problem); - + G_message(_("Reading training data")); + fill_problem(name_labels, mapset_labels, band_ref, mapset_group, + &problem); + /* svm_check_parameter needs filled svm_problem struct thus checking only now */ + G_verbose_message("Checking SVM parameterization"); parameters_error = svm_check_parameter(&problem, ¶meters); if (parameters_error) G_fatal_error(_("SVM parameter validation returned an error: %s\n"), parameters_error); - /* Train model */ + /* Train model. Might take some time. */ + G_message(_("Starting training process")); model = svm_train(&problem, ¶meters); /* Write out training results */ /* TODO: Move to Imagery library? */ - if (opt_subgroup->answer) - sprintf(element, "group%c%s%csubgroup%c%s%csvm", HOST_DIRSEP, name_group, HOST_DIRSEP, HOST_DIRSEP, opt_subgroup->answer, HOST_DIRSEP); - else - sprintf(element, "group%c%s%csvm", HOST_DIRSEP, name_group, HOST_DIRSEP); - if (G_make_mapset_element(element) == 0) - G_fatal_error(_("Failed to create signatures for group <%s>"), opt_group->answer); - G_file_name_misc(model_file, NULL, element, opt_sigfile->answer, G_mapset()); - out_status = svm_save_model(model_file, model); + G_verbose_message("Writing out trained SVM"); + if (G__make_mapset_element_misc(sigfile_dir, name_sigfile) == 0) + G_fatal_error(_("Failed to create signatures for group <%s>"), + opt_group->answer); + G_file_name_misc(out_file, sigfile_dir, "model", name_sigfile, + G_mapset()); + out_status = svm_save_model(out_file, model); if (out_status != 0) { - G_fatal_error(_("Unable to write trained model to file '%s'. Error code: %d"), model_file, out_status); + G_fatal_error(_("Unable to write trained model to file '%s'. Error code: %d"), + out_file, out_status); + } + + /* Copy CATs file. Will be used for prediction result maps */ + G_verbose_message("Copying category information"); + if (Rast_read_cats(name_labels, mapset_labels, &cats) == 0) { + /* Path to training label map CATs file */ + G_file_name(cats_path, "cats", name_labels, mapset_labels); + G_file_name_misc(out_file, sigfile_dir, "cats", name_sigfile, + G_mapset()); + G_copy_file(cats_path, out_file); } + + /* History will be appended to a prediction result map history */ + G_verbose_message("Writing out history"); + hist_file = G_fopen_new_misc(sigfile_dir, "history", name_sigfile); + if (hist_file != NULL) { + cmdline = G_recreate_command(); + fprintf(hist_file, "%s\n", cmdline); + fclose(hist_file); + } + else { + G_warning(_("Unable to write history information for <%s>"), + name_sigfile); + } + G_message(_("Training successfuly complete")); exit(EXIT_SUCCESS); } From 7eaf40868c784f7b8bdf60eac4cb0efcd81fca43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Sun, 31 Jan 2021 22:24:23 +0200 Subject: [PATCH 009/123] i.svm: Fix wrapping of transfered command history --- imagery/i.svm.predict/main.c | 6 +++++- imagery/i.svm.train/main.c | 10 +++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c index e6ffb15a032..fa19cf575d6 100644 --- a/imagery/i.svm.predict/main.c +++ b/imagery/i.svm.predict/main.c @@ -288,8 +288,9 @@ int main(int argc, char *argv[]) G_fopen_old_misc(sigfile_dir, "history", name_sigfile, mapset_sigfile); if (hist_file != NULL) { - if (G_getl(hist_line, sizeof(hist_line), hist_file)) + while (G_getl(hist_line, sizeof(hist_line), hist_file) == 1) { Rast_append_history(&history, hist_line); + } fclose(hist_file); } Rast_command_history(&history); @@ -311,6 +312,9 @@ int main(int argc, char *argv[]) mapset_sigfile); G_file_name(cats_path, "cats", name_values, G_mapset()); G_copy_file(cats_file, cats_path); /* It's still OK if it fails here */ + Rast_put_cell_title(name_values, + /* GTC: A map title */ + _("Values predicted with Support Vector Machine")); exit(EXIT_SUCCESS); } diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index 9a8d5cce793..4296b8e0eef 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -58,8 +58,9 @@ int main(int argc, char *argv[]) struct Categories cats; char cats_path[GPATH_MAX]; + struct History history; FILE *hist_file; - char *cmdline; + int i; G_gisinit(argv[0]); @@ -403,8 +404,11 @@ int main(int argc, char *argv[]) G_verbose_message("Writing out history"); hist_file = G_fopen_new_misc(sigfile_dir, "history", name_sigfile); if (hist_file != NULL) { - cmdline = G_recreate_command(); - fprintf(hist_file, "%s\n", cmdline); + G_zero(&history, sizeof(struct History)); + /* Rast_command_history performs command wrapping */ + Rast_command_history(&history); + for (i = 0; i < history.nlines; i++) + fprintf(hist_file, "%s\n", history.lines[i]); fclose(hist_file); } else { From af7dcb91ba53554f19606d39fcefb3ec98c473e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Sun, 31 Jan 2021 22:34:51 +0200 Subject: [PATCH 010/123] i.svm: One class classifier gives different values than where present in a training map --- imagery/i.svm.predict/main.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c index fa19cf575d6..e83c86d1807 100644 --- a/imagery/i.svm.predict/main.c +++ b/imagery/i.svm.predict/main.c @@ -306,12 +306,13 @@ int main(int argc, char *argv[]) Rast_write_history(name_values, &history); /* Copy CATs file from the original training map */ - /* TODO: figure out if ONE_CLASS also needs original CATs */ - G_verbose_message("Copying category information"); - G_file_name_misc(cats_file, sigfile_dir, "cats", name_sigfile, - mapset_sigfile); - G_file_name(cats_path, "cats", name_values, G_mapset()); - G_copy_file(cats_file, cats_path); /* It's still OK if it fails here */ + if (svm_type != ONE_CLASS) { + G_verbose_message("Copying category information"); + G_file_name_misc(cats_file, sigfile_dir, "cats", name_sigfile, + mapset_sigfile); + G_file_name(cats_path, "cats", name_values, G_mapset()); + G_copy_file(cats_file, cats_path); /* It's still OK if it fails to copy */ + } Rast_put_cell_title(name_values, /* GTC: A map title */ _("Values predicted with Support Vector Machine")); From 8043cd854a4a0b9974338bbe586366c33a6fe4ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Sun, 31 Jan 2021 22:58:13 +0200 Subject: [PATCH 011/123] i.svm: Copy colors from training map to prediction map --- imagery/i.svm.predict/main.c | 17 ++++++++++++----- imagery/i.svm.train/main.c | 18 ++++++++++++++---- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c index e83c86d1807..b7d530b4037 100644 --- a/imagery/i.svm.predict/main.c +++ b/imagery/i.svm.predict/main.c @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) char mapset_group[GMAPSET_MAX], mapset_subgroup[GMAPSET_MAX], mapset_values[GMAPSET_MAX]; char sigfile_dir[GPATH_MAX], model_file[GPATH_MAX]; - char cats_path[GPATH_MAX], cats_file[GPATH_MAX]; + char in_path[GPATH_MAX], out_path[GPATH_MAX]; struct Ref band_ref; @@ -305,13 +305,20 @@ int main(int argc, char *argv[]) name_sigfile, mapset_sigfile); Rast_write_history(name_values, &history); - /* Copy CATs file from the original training map */ if (svm_type != ONE_CLASS) { + /* Copy CATs file from the original training map */ G_verbose_message("Copying category information"); - G_file_name_misc(cats_file, sigfile_dir, "cats", name_sigfile, + G_file_name_misc(in_path, sigfile_dir, "cats", name_sigfile, mapset_sigfile); - G_file_name(cats_path, "cats", name_values, G_mapset()); - G_copy_file(cats_file, cats_path); /* It's still OK if it fails to copy */ + G_file_name(out_path, "cats", name_values, G_mapset()); + G_copy_file(in_path, out_path); /* It's still OK if it fails to copy */ + + /* Copy color file from the original training map */ + G_verbose_message("Copying color information"); + G_file_name_misc(in_path, sigfile_dir, "colr", name_sigfile, + mapset_sigfile); + G_file_name(out_path, "colr", name_values, G_mapset()); + G_copy_file(in_path, out_path); } Rast_put_cell_title(name_values, /* GTC: A map title */ diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index 4296b8e0eef..00a4819db58 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -57,7 +57,7 @@ int main(int argc, char *argv[]) int out_status; struct Categories cats; - char cats_path[GPATH_MAX]; + char in_path[GPATH_MAX], out_path[GPATH_MAX]; struct History history; FILE *hist_file; int i; @@ -394,10 +394,20 @@ int main(int argc, char *argv[]) G_verbose_message("Copying category information"); if (Rast_read_cats(name_labels, mapset_labels, &cats) == 0) { /* Path to training label map CATs file */ - G_file_name(cats_path, "cats", name_labels, mapset_labels); - G_file_name_misc(out_file, sigfile_dir, "cats", name_sigfile, + G_file_name(in_path, "cats", name_labels, mapset_labels); + G_file_name_misc(out_path, sigfile_dir, "cats", name_sigfile, G_mapset()); - G_copy_file(cats_path, out_file); + G_copy_file(in_path, out_path); + } + + /* Copy color file. Will be used for prediction result maps */ + G_verbose_message("Copying color information"); + if (G_find_file2("colr", name_labels, mapset_labels)) { + /* Path to training label map colr file */ + G_file_name(in_path, "colr", name_labels, mapset_labels); + G_file_name_misc(out_path, sigfile_dir, "colr", name_sigfile, + G_mapset()); + G_copy_file(in_path, out_path); } /* History will be appended to a prediction result map history */ From d68b34b8e360ef8ac5c20c1a0e33828b8b5c15b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Mon, 29 Mar 2021 15:17:28 +0300 Subject: [PATCH 012/123] Enable compilation of i.svm modules --- imagery/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imagery/Makefile b/imagery/Makefile index c1fb0120924..f708c668d9d 100644 --- a/imagery/Makefile +++ b/imagery/Makefile @@ -31,6 +31,8 @@ SUBDIRS = \ i.rgb.his \ i.segment \ i.smap \ + i.svm.predict \ + i.svm.train \ i.target \ i.topo.corr \ i.pca \ From 95c7eb4c6573bec1dae72e7078856d5da604b855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 10 Sep 2021 10:28:28 +0300 Subject: [PATCH 013/123] Do not capitalize libsvm --- configure.in | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/configure.in b/configure.in index 951b347089b..de252a21d4c 100644 --- a/configure.in +++ b/configure.in @@ -283,7 +283,7 @@ LOC_ARG_WITH(odbc, ODBC, no) LOC_ARG_WITH(fftw, FFTW) LOC_ARG_WITH(blas, BLAS, no) LOC_ARG_WITH(lapack, LAPACK, no) -LOC_ARG_WITH(libsvm, LIBSVM, no) +LOC_ARG_WITH(libsvm, libsvm, no) LOC_ARG_WITH(cairo, Cairo) LOC_ARG_WITH(freetype, FreeType) LOC_ARG_WITH(nls, NLS, no) @@ -382,8 +382,8 @@ LOC_ARG_WITH_LIB(blas, BLAS) LOC_ARG_WITH_INC(lapack, LAPACK) LOC_ARG_WITH_LIB(lapack, LAPACK) -LOC_ARG_WITH_INC(libsvm, LIBSVM) -LOC_ARG_WITH_LIB(libsvm, LIBSVM) +LOC_ARG_WITH_INC(libsvm, libsvm) +LOC_ARG_WITH_LIB(libsvm, libsvm) LOC_ARG_WITH_INC(cairo, cairo) LOC_ARG_WITH_LIB(cairo, cairo) @@ -1678,25 +1678,25 @@ AC_SUBST(LAPACKINC) # Done checking LAPACK -# LIBSVM option +# libsvm option LIBSVM_INC= LIBSVM_LIB= USE_LIBSVM= -LOC_CHECK_USE(libsvm,LIBSVM,USE_LIBSVM) +LOC_CHECK_USE(libsvm,libsvm,USE_LIBSVM) if test -n "$USE_LIBSVM"; then - LOC_CHECK_INC_PATH(libsvm,LIBSVM,LIBSVM_INC) - LOC_CHECK_INCLUDES(libsvm/svm.h,LIBSVM,$LIBSVM_INC) - LOC_CHECK_LIB_PATH(libsvm,LIBSVM,LIBSVM_LIB) - LOC_CHECK_LIBS(svm,svm_load_model,LIBSVM,$LIBSVM_LIB,LIBSVM_LIB,,,) + LOC_CHECK_INC_PATH(libsvm,libsvm,LIBSVM_INC) + LOC_CHECK_INCLUDES(libsvm/svm.h,libsvm,$LIBSVM_INC) + LOC_CHECK_LIB_PATH(libsvm,libsvm,LIBSVM_LIB) + LOC_CHECK_LIBS(svm,svm_load_model,libsvm,$LIBSVM_LIB,LIBSVM_LIB,,,) AC_DEFINE(HAVE_LIBSVM) fi AC_SUBST(LIBSVM_INC) AC_SUBST(LIBSVM_LIB) AC_SUBST(USE_LIBSVM) -# Done with LIBSVM +# Done with libsvm # Enable Cairo display driver option @@ -2054,7 +2054,7 @@ LOC_MSG_USE(GEOS support,USE_GEOS) LOC_MSG_USE(LAPACK support,USE_LAPACK) LOC_MSG_USE(Large File support (LFS), USE_LARGEFILES) LOC_MSG_USE(libLAS support,USE_LIBLAS) -LOC_MSG_USE(LIBSVM support,USE_LIBSVM) +LOC_MSG_USE(Libsvm support,USE_LIBSVM) LOC_MSG_USE(MySQL support,USE_MYSQL) LOC_MSG_USE(NetCDF support,USE_NETCDF) LOC_MSG_USE(NLS support,USE_NLS) From 76bf08df3b1035aac253be5e630f3d95a3280c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Thu, 2 Sep 2021 16:08:03 +0300 Subject: [PATCH 014/123] Imagery: libsvm signature handling As libsvm signatures will consist of multiple files, modification to management functions was necessary. --- include/grass/imagery.h | 3 +- lib/imagery/manage_signatures.c | 3 + lib/imagery/testsuite/test_imagery_find.py | 55 +++ .../test_imagery_signature_management.py | 329 ++++++++++++++++++ 4 files changed, 389 insertions(+), 1 deletion(-) diff --git a/include/grass/imagery.h b/include/grass/imagery.h index 20b1623832f..dd471f602d2 100644 --- a/include/grass/imagery.h +++ b/include/grass/imagery.h @@ -203,11 +203,12 @@ typedef enum { I_SIGFILE_TYPE_SIG, /*! Signature files used by i.maxlik */ I_SIGFILE_TYPE_SIGSET, /*! Signature files used by i.smap */ + I_SIGFILE_TYPE_LIBSVM, /*! Signature files used by i.svm */ } I_SIGFILE_TYPE; #define SIGNATURE_TYPE_MIXED 1 /* Unused? */ -#define I_SIGFILE_TYPE_COUNT 2 /*! Total count of supported signature file types */ +#define I_SIGFILE_TYPE_COUNT 3 /*! Total count of supported signature file types */ #define GROUPFILE "CURGROUP" diff --git a/lib/imagery/manage_signatures.c b/lib/imagery/manage_signatures.c index c9dd280a716..d260f2df3ba 100644 --- a/lib/imagery/manage_signatures.c +++ b/lib/imagery/manage_signatures.c @@ -34,6 +34,9 @@ void I_get_signatures_dir(char *dir, I_SIGFILE_TYPE type) else if (type == I_SIGFILE_TYPE_SIGSET) { sprintf(dir, "signatures%csigset", HOST_DIRSEP); } + else if (type == I_SIGFILE_TYPE_LIBSVM) { + sprintf(element, "signatures%clibsvm", HOST_DIRSEP); + } else { G_fatal_error("Programming error: unknown signature file type"); } diff --git a/lib/imagery/testsuite/test_imagery_find.py b/lib/imagery/testsuite/test_imagery_find.py index 479eba62a28..a943e2d3520 100644 --- a/lib/imagery/testsuite/test_imagery_find.py +++ b/lib/imagery/testsuite/test_imagery_find.py @@ -22,6 +22,7 @@ from grass.lib.imagery import ( I_SIGFILE_TYPE_SIG, I_SIGFILE_TYPE_SIGSET, + I_SIGFILE_TYPE_LIBSVM, I_find_signature, I_find_signature2, ) @@ -37,6 +38,7 @@ def setUpClass(cls): # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) os.makedirs(f"{cls.mpath}/signatures/sigset/", exist_ok=True) + os.makedirs(f"{cls.mpath}/signatures/libsvm/", exist_ok=True) cls.sig_name1 = tempname(10) cls.sig_dir1 = f"{cls.mpath}/signatures/sigset/{cls.sig_name1}" os.makedirs(cls.sig_dir1) @@ -47,6 +49,11 @@ def setUpClass(cls): os.makedirs(cls.sig_dir2) cls.sigdirs.append(cls.sig_dir2) open(f"{cls.sig_dir2}/sig", "a").close() + cls.sig_name3 = tempname(10) + cls.sig_dir3 = f"{cls.mpath}/signatures/libsvm/{cls.sig_name3}" + os.makedirs(cls.sig_dir3) + cls.sigdirs.append(cls.sig_dir3) + open(f"{cls.sig_dir3}/sig", "a").close() @classmethod def tearDownClass(cls): @@ -101,6 +108,30 @@ def test_find_sigset(self): ret = I_find_signature(I_SIGFILE_TYPE_SIGSET, self.sig_name1, "PERMANENT") self.assertFalse(ret) + def test_find_libsvm(self): + # Non existing without a mapset + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, tempname(10), None) + self.assertFalse(ret) + # Non existing with a mapset + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, tempname(10), self.mapset_name) + self.assertFalse(ret) + # Libsvm with sig type should equal non existing + ret = I_find_signature(I_SIGFILE_TYPE_SIG, self.sig_name3, self.mapset_name) + self.assertFalse(ret) + # Existing without a mapset + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, self.sig_name3, None) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + # Existing with a mapset + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, self.sig_name3, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + # Existing in a different mapset should fail + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, self.sig_name3, "PERMANENT") + self.assertFalse(ret) + def test_find2_sig(self): # Non existing without a mapset ret = I_find_signature2(I_SIGFILE_TYPE_SIG, tempname(10), None) @@ -149,6 +180,30 @@ def test_find2_sigset(self): ret = I_find_signature2(I_SIGFILE_TYPE_SIGSET, self.sig_name1, "PERMANENT") self.assertFalse(ret) + def test_find2_libsvm(self): + # Non existing without a mapset + ret = I_find_signature2(I_SIGFILE_TYPE_LIBSVM, tempname(10), None) + self.assertFalse(ret) + # Non existing with a mapset + ret = I_find_signature2(I_SIGFILE_TYPE_LIBSVM, tempname(10), self.mapset_name) + self.assertFalse(ret) + # Libsvm with sig type should equal non existing + ret = I_find_signature2(I_SIGFILE_TYPE_SIG, self.sig_name3, self.mapset_name) + self.assertFalse(ret) + # Existing without a mapset + ret = I_find_signature2(I_SIGFILE_TYPE_LIBSVM, self.sig_name3, None) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + # Existing with a mapset + ret = I_find_signature2(I_SIGFILE_TYPE_LIBSVM, self.sig_name3, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + # Existing in a different mapset should fail + ret = I_find_signature2(I_SIGFILE_TYPE_LIBSVM, self.sig_name3, "PERMANENT") + self.assertFalse(ret) + if __name__ == "__main__": test() diff --git a/lib/imagery/testsuite/test_imagery_signature_management.py b/lib/imagery/testsuite/test_imagery_signature_management.py index ae926afd6e8..c00d19adbc6 100644 --- a/lib/imagery/testsuite/test_imagery_signature_management.py +++ b/lib/imagery/testsuite/test_imagery_signature_management.py @@ -30,6 +30,7 @@ from grass.lib.imagery import ( I_SIGFILE_TYPE_SIG, I_SIGFILE_TYPE_SIGSET, + I_SIGFILE_TYPE_LIBSVM, I_find_signature, I_signatures_remove, I_signatures_copy, @@ -52,6 +53,11 @@ def test_get_sigset(self): I_get_signatures_dir(cdir, I_SIGFILE_TYPE_SIGSET) self.assertEqual(utils.decode(cdir.value), f"signatures{HOST_DIRSEP}sigset") + def test_get_libsvm(self): + elem = ctypes.create_string_buffer(GNAME_MAX) + I__get_signatures_element(elem, I_SIGFILE_TYPE_LIBSVM) + self.assertEqual(utils.decode(elem.value), f"signatures{HOST_DIRSEP}libsvm") + class MakeSignaturesElementTestCase(TestCase): @classmethod @@ -90,6 +96,17 @@ def test_make_sigset(self): os.path.isdir(os.path.join(self.tmp_mapset_path, "signatures", "sigset")) ) + def test_make_libsvm(self): + I__make_signatures_element(I_SIGFILE_TYPE_LIBSVM) + self.assertTrue( + os.path.isdir(os.path.join(self.tmp_mapset_path, "signatures", "libsvm")) + ) + # There should not be any side effects of calling function multiple times + I__make_signatures_element(I_SIGFILE_TYPE_SIGSET) + self.assertTrue( + os.path.isdir(os.path.join(self.tmp_mapset_path, "signatures", "libsvm")) + ) + class SignaturesRemoveTestCase(TestCase): @classmethod @@ -101,6 +118,7 @@ def setUpClass(cls): # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) os.makedirs(f"{cls.mpath}/signatures/sigset/", exist_ok=True) + os.makedirs(f"{cls.mpath}/signatures/libsvm/", exist_ok=True) @classmethod def tearDownClass(cls): @@ -266,6 +284,82 @@ def test_remove_nonexisting_sigset(self): ms = utils.decode(ret) self.assertEqual(ms, self.mapset_name) + def test_remove_existing_libsvm(self): + # This test will fail if run in PERMANENT! + # Set up files and mark for clean-up + sig_name1 = tempname(10) + sig_dir1 = f"{self.mpath}/signatures/libsvm/{sig_name1}" + os.makedirs(sig_dir1) + sigfile_name1 = f"{sig_dir1}/sig" + open(sigfile_name1, "a").close() + self.sigdirs.append(sig_dir1) + sig_name2 = tempname(10) + sig_dir2 = f"{self.mpath}/signatures/libsvm/{sig_name2}" + os.makedirs(sig_dir2) + sigfile_name2 = f"{sig_dir2}/sig" + open(sigfile_name2, "a").close() + self.sigdirs.append(sig_dir2) + sig_name3 = tempname(10) + sigfile_name3 = f"{self.mpath}/signatures/sig/{sig_name3}" + open(sigfile_name3, "a").close() + self.sigfiles.append(sigfile_name3) + # Try to remove with wrong type + ret = I_signatures_remove(I_SIGFILE_TYPE_SIG, sig_name2) + self.assertEqual(ret, 1) + # Try to remove with wrong mapset + ret = I_signatures_remove(I_SIGFILE_TYPE_LIBSVM, f"{sig_name2}@PERMANENT") + self.assertEqual(ret, 1) + # Should be still present + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, sig_name2, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + # Now remove with correct type + ret = I_signatures_remove(I_SIGFILE_TYPE_LIBSVM, sig_name2) + self.assertEqual(ret, 0) + # removed should be gone + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, sig_name2, self.mapset_name) + self.assertFalse(ret) + # Others should remain + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, sig_name1, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + ret = I_find_signature(I_SIGFILE_TYPE_SIG, sig_name3, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + + def test_remove_nonexisting_libsvm(self): + # Set up files and mark for clean-up + sig_name1 = tempname(10) + sigfile_name1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + open(sigfile_name1, "a").close() + self.sigfiles.append(sigfile_name1) + sig_name2 = tempname(10) + # Do not create sig_name2 matching file + sig_name3 = tempname(10) + sig_dir3 = f"{self.mpath}/signatures/libsvm/{sig_name3}" + os.makedirs(sig_dir3) + sigfile_name3 = f"{sig_dir3}/sig" + open(sigfile_name3, "a").close() + self.sigdirs.append(sig_dir3) + # Now remove one (should fail as file is absent) + ret = I_signatures_remove(I_SIGFILE_TYPE_LIBSVM, sig_name2) + self.assertEqual(ret, 1) + # removed should be still absent + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, sig_name2, self.mapset_name) + self.assertFalse(ret) + # All others should remain + ret = I_find_signature(I_SIGFILE_TYPE_SIGSET, sig_name1, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, sig_name3, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + class SignaturesCopyTestCase(TestCase): @classmethod @@ -277,6 +371,7 @@ def setUpClass(cls): # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) os.makedirs(f"{cls.mpath}/signatures/sigset/", exist_ok=True) + os.makedirs(f"{cls.mpath}/signatures/libsvm/", exist_ok=True) # A mapset with a random name cls.src_mapset_name = tempname(10) G_make_mapset(None, None, cls.src_mapset_name) @@ -300,6 +395,14 @@ def setUpClass(cls): f = open(f"{cls.src_sigset_dir}/sig", "w") f.write("A sigset file") f.close() + os.makedirs(f"{cls.src_mapset_path}/signatures/libsvm/") + cls.src_libsvm = tempname(10) + cls.src_libsvm_dir = f"{cls.src_mapset_path}/signatures/libsvm/{cls.src_libsvm}" + os.makedirs(cls.src_libsvm_dir) + cls.sigdirs.append(cls.src_libsvm_dir) + f = open(f"{cls.src_libsvm_dir}/sig", "w") + f.write("A libsvm file") + f.close() @classmethod def tearDownClass(cls): @@ -327,6 +430,12 @@ def test_sigset_does_not_exist(self): ) self.assertEqual(ret, 1) + def test_libsvm_does_not_exist(self): + ret = I_signatures_copy( + I_SIGFILE_TYPE_LIBSVM, tempname(10), self.mapset_name, tempname(10) + ) + self.assertEqual(ret, 1) + def test_success_unqualified_sig(self): dst = tempname(10) ret = I_find_signature(I_SIGFILE_TYPE_SIG, dst, self.mapset_name) @@ -409,6 +518,49 @@ def test_success_fq_sigset(self): os.path.isfile(f"{self.mpath}/signatures/sigset/{dst_name}/sig") ) + def test_success_unqualified_libsvm(self): + dst = tempname(10) + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, dst, self.mapset_name) + self.assertFalse(ret) + ret = I_find_signature( + I_SIGFILE_TYPE_LIBSVM, self.src_libsvm, self.src_mapset_name + ) + self.assertTrue(ret) + ret = I_signatures_copy( + I_SIGFILE_TYPE_LIBSVM, self.src_libsvm, self.src_mapset_name, dst + ) + self.sigdirs.append(f"{self.mpath}/signatures/libsvm/{dst}") + self.assertEqual(ret, 0) + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, dst, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{self.mpath}/signatures/libsvm/{dst}/sig")) + + def test_success_fq_sig(self): + dst = tempname(10) + dst_dir = f"{self.mpath}/signatures/libsvm/{dst}" + self.sigdirs.append(dst_dir) + dst = dst + "@" + self.mapset_name + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, dst, self.mapset_name) + self.assertFalse(ret) + ret = I_find_signature( + I_SIGFILE_TYPE_LIBSVM, self.src_libsvm, self.src_mapset_name + ) + self.assertTrue(ret) + ret = I_signatures_copy( + I_SIGFILE_TYPE_LIBSVM, + self.src_libsvm + "@" + self.src_mapset_name, + self.src_mapset_name, + dst, + ) + self.assertEqual(ret, 0) + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, dst, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{dst_dir}/sig")) + class SignaturesRenameTestCase(TestCase): @classmethod @@ -420,6 +572,7 @@ def setUpClass(cls): # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) os.makedirs(f"{cls.mpath}/signatures/sigset/", exist_ok=True) + os.makedirs(f"{cls.mpath}/signatures/libsvm/", exist_ok=True) @classmethod def tearDownClass(cls): @@ -444,6 +597,10 @@ def test_sigset_does_not_exist(self): ret = I_signatures_rename(I_SIGFILE_TYPE_SIGSET, tempname(10), tempname(10)) self.assertEqual(ret, 1) + def test_libsvm_does_not_exist(self): + ret = I_signatures_rename(I_SIGFILE_TYPE_LIBSVM, tempname(10), tempname(10)) + self.assertEqual(ret, 1) + def test_success_unqualified_sig(self): src_sig = tempname(10) sig_dir = f"{self.mpath}/signatures/sig/{src_sig}" @@ -544,6 +701,56 @@ def test_success_fq_sigset(self): os.path.isfile(f"{self.mpath}/signatures/sigset/{dst_name}/sig") ) + def test_success_unqualified_libsvm(self): + src_sig = tempname(10) + sig_dir = f"{self.mpath}/signatures/libsvm/{src_sig}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") + f.write("A libsvm file") + f.close() + dst = tempname(10) + self.sigdirs.append(f"{self.mpath}/signatures/libsvm/{dst}") + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, dst, self.mapset_name) + self.assertFalse(ret) + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, src_sig, self.mapset_name) + self.assertTrue(ret) + ret = I_signatures_rename(I_SIGFILE_TYPE_LIBSVM, src_sig, dst) + self.assertEqual(ret, 0) + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, dst, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{self.mpath}/signatures/libsvm/{dst}/sig")) + + def test_success_fq_libsvm(self): + src_sig = tempname(10) + sig_dir = f"{self.mpath}/signatures/libsvm/{src_sig}" + os.makedirs(sig_dir) + self.sigdirs.append(sig_dir) + f = open(f"{sig_dir}/sig", "w") + f.write("A libsvm file") + f.close() + dst = tempname(10) + dst_dir = f"{self.mpath}/signatures/libsvm/{dst}" + self.sigdirs.append(dst_dir) + dst = dst + "@" + self.mapset_name + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, dst, self.mapset_name) + self.assertFalse(ret) + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, src_sig, self.mapset_name) + self.assertTrue(ret) + ret = I_signatures_rename( + I_SIGFILE_TYPE_LIBSVM, + src_sig + "@" + self.mapset_name, + dst, + ) + self.assertEqual(ret, 0) + ret = I_find_signature(I_SIGFILE_TYPE_LIBSVM, dst, self.mapset_name) + self.assertTrue(ret) + ms = utils.decode(ret) + self.assertEqual(ms, self.mapset_name) + self.assertTrue(os.path.isfile(f"{dst_dir}/sig")) + class SignaturesListByTypeTestCase(TestCase): @classmethod @@ -556,6 +763,7 @@ def setUpClass(cls): # tools, we must ensure signature directories exist os.makedirs(f"{cls.mpath}/signatures/sig/", exist_ok=True) os.makedirs(f"{cls.mpath}/signatures/sigset/", exist_ok=True) + os.makedirs(f"{cls.mpath}/signatures/libsvm/", exist_ok=True) # A mapset with a random name cls.rnd_mapset_name = tempname(10) G_make_mapset(None, None, cls.rnd_mapset_name) @@ -564,6 +772,7 @@ def setUpClass(cls): ) os.makedirs(f"{cls.rnd_mapset_path}/signatures/sig/") os.makedirs(f"{cls.rnd_mapset_path}/signatures/sigset/") + os.makedirs(f"{cls.rnd_mapset_path}/signatures/libsvm/") @classmethod def tearDownClass(cls): @@ -586,6 +795,11 @@ def test_no_sigs_at_all(self): ) self.assertEqual(ret, 0) I_free_signatures_list(ret, ctypes.byref(sig_list)) + ret = I_signatures_list_by_type( + I_SIGFILE_TYPE_LIBSVM, self.rnd_mapset_name, ctypes.byref(sig_list) + ) + self.assertEqual(ret, 0) + I_free_signatures_list(ret, ctypes.byref(sig_list)) def test_sig_in_different_mapset(self): # Should return 0 signatures from a different mapset @@ -619,6 +833,22 @@ def test_sig_in_different_mapset(self): shutil.rmtree(sig_dir) self.assertEqual(ret, 0) I_free_signatures_list(ret, ctypes.byref(sig_list)) + # Libsvm type + local_sig = tempname(10) + sig_dir = f"{self.mpath}/signatures/libsvm/{local_sig}" + os.makedirs(sig_dir) + sig_file = f"{sig_dir}/sig" + self.sigdirs.append(sig_dir) + f = open(sig_file, "w") + f.write("A libsvm file") + f.close() + sig_list = self.list_ptr() + ret = I_signatures_list_by_type( + I_SIGFILE_TYPE_LIBSVM, self.rnd_mapset_name, ctypes.byref(sig_list) + ) + os.remove(sig_file) + self.assertEqual(ret, 0) + I_free_signatures_list(ret, ctypes.byref(sig_list)) def test_single_sig(self): # Case when only a single signature file is present @@ -657,6 +887,23 @@ def test_single_sig(self): val = utils.decode(sigset_list[0]) self.assertEqual(val, f"{rnd_sigset}@{self.rnd_mapset_name}") I_free_signatures_list(ret, ctypes.byref(sigset_list)) + # libsvm type + rnd_sig = tempname(10) + sig_dir = f"{self.rnd_mapset_path}/signatures/libsvm/{rnd_sig}" + os.makedirs(sig_dir) + sig_file = f"{sig_dir}/sig" + f = open(sig_file, "w") + f.write("A libsvm file") + f.close() + sig_list = self.list_ptr() + ret = I_signatures_list_by_type( + I_SIGFILE_TYPE_LIBSVM, self.rnd_mapset_name, ctypes.byref(sig_list) + ) + shutil.rmtree(sig_dir) + self.assertEqual(ret, 1) + val = utils.decode(sig_list[0]) + self.assertEqual(val, f"{rnd_sig}@{self.rnd_mapset_name}") + I_free_signatures_list(ret, ctypes.byref(sig_list)) def test_multiple_sigs(self): # Should result into a multiple sigs returned @@ -719,6 +966,36 @@ def test_multiple_sigs(self): self.assertIn(utils.decode(sigset_list[0]), golden) self.assertIn(utils.decode(sigset_list[1]), golden) I_free_signatures_list(ret, ctypes.byref(sigset_list)) + # libsvm type + rnd_sig1 = tempname(10) + sig_dir1 = f"{self.rnd_mapset_path}/signatures/libsvm/{rnd_sig1}" + os.makedirs(sig_dir1) + sig_file1 = f"{sig_dir1}/sig" + f = open(sig_file1, "w") + f.write("A libsvm file") + f.close() + rnd_sig2 = tempname(10) + sig_dir2 = f"{self.rnd_mapset_path}/signatures/libsvm/{rnd_sig2}" + os.makedirs(sig_dir2) + sig_file2 = f"{sig_dir2}/sig" + f = open(sig_file2, "w") + f.write("A libsvm file") + f.close() + # POINTER(POINTER(c_char)) + sig_list = self.list_ptr() + ret = I_signatures_list_by_type( + I_SIGFILE_TYPE_LIBSVM, self.rnd_mapset_name, ctypes.byref(sig_list) + ) + shutil.rmtree(sig_dir1) + shutil.rmtree(sig_dir2) + self.assertEqual(ret, 2) + golden = ( + f"{rnd_sig1}@{self.rnd_mapset_name}", + f"{rnd_sig2}@{self.rnd_mapset_name}", + ) + self.assertIn(utils.decode(sig_list[0]), golden) + self.assertIn(utils.decode(sig_list[1]), golden) + I_free_signatures_list(ret, ctypes.byref(sig_list)) def test_multiple_sigs_multiple_mapsets(self): # Test searching in multiple mapsets. Identical to SIGSET case @@ -822,6 +1099,58 @@ def test_multiple_sigsets_multiple_mapsets(self): self.assertIn(golden[1], ret_list) I_free_signatures_list(ret, ctypes.byref(sig_list)) + def test_multiple_libsvms_multiple_mapsets(self): + # Test searching in multiple mapsets. Identical to SIG and SIGSET case + rnd_sig1 = tempname(10) + sig_dir1 = f"{self.rnd_mapset_path}/signatures/libsvm/{rnd_sig1}" + os.makedirs(sig_dir1) + sig_file1 = f"{sig_dir1}/sig" + f = open(sig_file1, "w") + f.write("A libsvm file") + f.close() + rnd_sig2 = tempname(10) + sig_dir2 = f"{self.mpath}/signatures/libsvm/{rnd_sig2}" + os.makedirs(sig_dir2) + sig_file2 = f"{sig_dir2}/sig" + f = open(sig_file2, "w") + f.write("A libsvm file") + f.close() + self.sigdirs.append(sig_dir2) + sig_list = self.list_ptr() + ret = I_signatures_list_by_type( + I_SIGFILE_TYPE_LIBSVM, None, ctypes.byref(sig_list) + ) + # As temporary mapset is not in the search path, there must be + # at least one sig file present + # There could be more sigs if this is not an empty mapset + self.assertTrue(ret >= 1) + ret_list = list(map(utils.decode, sig_list[:ret])) + golden = ( + f"{rnd_sig1}@{self.rnd_mapset_name}", + f"{rnd_sig2}@{self.mapset_name}", + ) + self.assertIn(golden[1], ret_list) + # Temporary mapset is not in the search path: + self.assertNotIn(golden[0], ret_list) + I_free_signatures_list(ret, ctypes.byref(sig_list)) + # Add temporary mapset to search path and re-run test + grass.run_command("g.mapsets", mapset=self.rnd_mapset_name, operation="add") + # Search path is cached for this run => reset! + G_reset_mapsets() + ret = I_signatures_list_by_type( + I_SIGFILE_TYPE_LIBSVM, None, ctypes.byref(sig_list) + ) + grass.run_command("g.mapsets", mapset=self.rnd_mapset_name, operation="remove") + G_reset_mapsets() + shutil.rmtree(sig_dir1) + shutil.rmtree(sig_dir2) + # There could be more sigs if this is not an empty mapset + self.assertTrue(ret >= 2) + ret_list = list(map(utils.decode, sig_list[:ret])) + self.assertIn(golden[0], ret_list) + self.assertIn(golden[1], ret_list) + I_free_signatures_list(ret, ctypes.byref(sig_list)) + if __name__ == "__main__": test() From b7ac7ddfe0694883a59bf73991c708e70e5e0ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 3 Sep 2021 16:51:29 +0300 Subject: [PATCH 015/123] i.svm.train: finalize implementation * use the new portable signature file layout in the mapset * add simple tests * add documentation --- imagery/i.svm.train/fill.c | 2 +- imagery/i.svm.train/i.svm.train.html | 109 ++++++++++ imagery/i.svm.train/main.c | 130 +++++++----- .../i.svm.train/testsuite/test_i_svm_train.py | 188 ++++++++++++++++++ 4 files changed, 375 insertions(+), 54 deletions(-) create mode 100644 imagery/i.svm.train/i.svm.train.html create mode 100644 imagery/i.svm.train/testsuite/test_i_svm_train.py diff --git a/imagery/i.svm.train/fill.c b/imagery/i.svm.train/fill.c index 59d4de0f6c8..1aa3ac84ac4 100644 --- a/imagery/i.svm.train/fill.c +++ b/imagery/i.svm.train/fill.c @@ -77,7 +77,7 @@ void fill_problem(const char *name_labels, const char *mapset_labels, if (Rast_is_d_null_value(&buf_bands[band][col])) continue; if (value_num >= value_max) { - /* Three bands are typical, thus we need 4 nodes */ + /* Three bands are typical, thus we start with 4 nodes */ value_max += 4; problem->x[label_num] = G_realloc(problem->x[label_num], ((size_t)value_max + diff --git a/imagery/i.svm.train/i.svm.train.html b/imagery/i.svm.train/i.svm.train.html new file mode 100644 index 00000000000..527286e66c4 --- /dev/null +++ b/imagery/i.svm.train/i.svm.train.html @@ -0,0 +1,109 @@ +

DESCRIPTION

+ +

i.svm.train finds parameters for a Support Vector Machine +and stores them in a signature file for later usage by +i.svm.predict. +

+ +

NOTES

+ +

i.svm.train internally is using the libsvm. For introduction +into value prediction or estimation with libsvm, see +a +Practical Guide to Support Vector Classification by +Chih-Wei Hsu, Chih-Chung Chang, and Chih-Jen Lin.

+ +

The module requires all training data (feature value) rasters to +have band references set. Use r.support +to set band references if you get an error of missing band reference.

+ +

PERFORMANCE

+ +

SVM training is done by loading all training data into memory. +In a case of large input raster files, use sparse label rasters +(e.g. raster points or small patches instead of uninterrupted cover).

+ +

During the training process there is no progress output printed. +Training with large number of data points can take significant time - +just be patient.

+ +

EXAMPLE

+ +

This is the first part of classification process. See +i.svm.predict for the second part.

+ +

Train a SVM to identify land use classes according to the 1996 land +use map landuse_96_28m and then classify a LANDSAT scene from +October of 2002. Example requires the nc_spm_08 location.

+
+## Prepare imagery for classification
+# Skip this step if your rasters already have band references defined
+# Define band references for all LANDSAT bands in mapset PERMANENT
+g.mapset mapset=PERMANENT
+r.support map=lsat7_2002_10 bandref=TM7_1
+r.support map=lsat7_2002_20 bandref=TM7_2
+r.support map=lsat7_2002_30 bandref=TM7_3
+r.support map=lsat7_2002_40 bandref=TM7_4
+r.support map=lsat7_2002_50 bandref=TM7_5
+r.support map=lsat7_2002_61 bandref=TM7_61
+r.support map=lsat7_2002_62 bandref=TM7_62
+r.support map=lsat7_2002_70 bandref=TM7_7
+r.support map=lsat7_2002_80 bandref=TM7_8
+g.mapset mapset=user1  # replace user1 with your mapset name
+
+## Real work starts here
+# Align computation region to the scene
+g.region raster=lsat7_2002_10 -p
+
+# store VIZ, NIR, MIR into group/subgroup
+i.group group=lsat7_2002 subgroup=res_30m \
+    input=lsat7_2002_10,lsat7_2002_20,lsat7_2002_30,lsat7_2002_40,lsat7_2002_50,lsat7_2002_70
+
+# Now digitize training areas "training" with the digitizer
+# and convert to raster model with v.to.rast
+v.to.rast input=training output=training use=cat label_column=label
+# If you are just playing around and do not care about the accuracy of outcome,
+# just use one of existing maps instead e.g.
+# r.random input=landuse96_28m npoints=5000 raster=training
+
+# Train the SVM
+i.svm.train group=lsat7_2002 subgroup=lsat7_2002\
+    input=training signaturefile=landuse_96_rnd_points
+
+# Go to i.svm.predict for the next step.
+
+ +

SEE ALSO

+ + +Predict values: i.svm.predict
+Set band references: r.support
+Other classification modules: i.maxlik, +i.smap +

+Libsvm home page: LIBSVM - A +Library for Support Vector Machines + +

REFERENCES

+ +

Please cite both - libsvm and i.svm.

+
    +
  • + For i.svm.* modules:
    + TODO. +
  • +
  • + For libsvm:
    + C.-C. Chang and C.-J. Lin. LIBSVM : a library for support vector machines. + ACM Transactions on Intelligent Systems and Technology, 2:27:1--27:27, 2011. +
  • +
+ +

AUTHORS

+ +Maris Nartiss, University of Latvia. + + diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index 00a4819db58..c14c6405aa4 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -5,12 +5,15 @@ * AUTHOR(S): Maris Nartiss - maris.gis gmail.com * PURPOSE: Trains Support Vector Machine classifier * - * COPYRIGHT: (C) 2020 by Maris Nartiss and the GRASS Development Team + * COPYRIGHT: (C) 2021 by Maris Nartiss and the GRASS Development Team * * This program is free software under the GNU General Public * License (>=v2). Read the file COPYING that comes with GRASS * for details. * + * Development supported from science funding of + * University of Latvia (2020/2021). + * *****************************************************************************/ #include #include @@ -24,7 +27,7 @@ #include "fill.h" -/* LIBSVM message wrapper */ +/* libsvm message wrapper */ void print_func(const char *s) { G_verbose_message("%s", s); @@ -40,13 +43,17 @@ int main(int argc, char *argv[]) *opt_svm_coef0, *opt_svm_eps, *opt_svm_cost, *opt_svm_nu, *opt_svm_p; struct Flag *flag_svm_shrink, *flag_svm_prob; - const char *mapset_labels, *name_sigfile; - char name_labels[GNAME_MAX], name_group[GNAME_MAX], - name_subgroup[GNAME_MAX]; - char mapset_group[GMAPSET_MAX], mapset_subgroup[GMAPSET_MAX]; - char sigfile_dir[GPATH_MAX], out_file[GPATH_MAX]; + const char *mapset_labels; + char name_labels[GNAME_MAX + GMAPSET_MAX]; + char name_group[GNAME_MAX], name_subgroup[GNAME_MAX], + name_sigfile[GNAME_MAX]; + char mapset_group[GMAPSET_MAX], mapset_subgroup[GMAPSET_MAX], + mapset_sigfile[GMAPSET_MAX]; + char sigfile_dir[GPATH_MAX]; + char in_path[GPATH_MAX], out_path[GPATH_MAX]; - struct Ref band_ref; + struct Ref group_ref; + const char **bandrefs; struct svm_parameter parameters; const char *parameters_error; @@ -57,9 +64,8 @@ int main(int argc, char *argv[]) int out_status; struct Categories cats; - char in_path[GPATH_MAX], out_path[GPATH_MAX]; struct History history; - FILE *hist_file; + FILE *misc_file; int i; G_gisinit(argv[0]); @@ -69,7 +75,7 @@ int main(int argc, char *argv[]) G_add_keyword(_("svm")); G_add_keyword(_("classification")); G_add_keyword(_("training")); - module->description = _("Train SVM"); + module->description = _("Train a SVM"); opt_group = G_define_standard_option(G_OPT_I_GROUP); /* GTC: SVM training input */ @@ -82,13 +88,13 @@ int main(int argc, char *argv[]) opt_labels->description = _("Map with training labels or target values"); opt_sigfile = G_define_option(); - opt_sigfile->key = "model"; + opt_sigfile->key = "signaturefile"; opt_sigfile->type = TYPE_STRING; opt_sigfile->key_desc = "name"; opt_sigfile->required = YES; - opt_sigfile->gisprompt = "new,rsvm,sigfile"; + opt_sigfile->gisprompt = "new,signatures/libsvm,sigfile"; opt_sigfile->description = - _("Name for output file containing trained model"); + _("Name for output file containing result signatures"); opt_svm_type = G_define_option(); opt_svm_type->key = "type"; @@ -118,13 +124,13 @@ int main(int argc, char *argv[]) opt_svm_kernel->type = TYPE_STRING; opt_svm_kernel->key_desc = "name"; opt_svm_kernel->required = NO; - opt_svm_kernel->options = "linear,poly,rbf,sigmoid,precomputed"; + opt_svm_kernel->options = "linear,poly,rbf,sigmoid"; opt_svm_kernel->answer = "rbf"; opt_svm_kernel->description = _("SVM kernel type"); opt_svm_kernel->guisection = _("SVM parameters"); G_asprintf((char **)&(opt_svm_kernel->descriptions), "linear;%s;" - "poly;%s;" "rbf;%s;" "sigmoid;%s;" "precomputed;%s;", + "poly;%s;" "rbf;%s;" "sigmoid;%s;" /* "precomputed;%s;" */ , /* GTC: SVM kernel type */ _("u'*v"), /* GTC: SVM kernel type */ @@ -132,9 +138,8 @@ int main(int argc, char *argv[]) /* GTC: SVM kernel type */ _("exp(-gamma*|u-v|^2)"), /* GTC: SVM kernel type */ - _("tanh(gamma*u'*v + coef0)"), - /* GTC: SVM kernel type */ - _("TODO: precomputed")); + _("tanh(gamma*u'*v + coef0)")); + /* TODO: precomputed */ opt_svm_cache_size = G_define_option(); opt_svm_cache_size->key = "cache"; @@ -144,7 +149,6 @@ int main(int argc, char *argv[]) opt_svm_cache_size->options = "1-999999999"; opt_svm_cache_size->answer = "512"; opt_svm_cache_size->description = _("Kernel cache size in MB"); - /* opt_svm_cache_size->guisection = _("SVM options"); */ opt_svm_degree = G_define_option(); opt_svm_degree->key = "degree"; @@ -263,19 +267,12 @@ int main(int argc, char *argv[]) G_fatal_error(_("Raster map <%s> not found"), opt_labels->answer); } - name_sigfile = opt_sigfile->answer; - if (opt_subgroup->answer) - sprintf(sigfile_dir, "group%c%s%csubgroup%c%s%crsvm", HOST_DIRSEP, - name_group, HOST_DIRSEP, HOST_DIRSEP, opt_subgroup->answer, - HOST_DIRSEP); - else - sprintf(sigfile_dir, "group%c%s%crsvm", HOST_DIRSEP, name_group, - HOST_DIRSEP); - if (!G_get_overwrite() && - G_find_file2_misc(sigfile_dir, "model", name_sigfile, - G_mapset()) != NULL) - G_fatal_error(_("option <%s>: <%s> exists. To overwrite, use the --overwrite flag"), - opt_sigfile->key, name_sigfile); + if (G_unqualified_name + (opt_sigfile->answer, G_mapset(), name_sigfile, mapset_sigfile) < 0) + G_fatal_error(_("<%s> does not match the current mapset"), + mapset_sigfile); + if (G_legal_filename(name_sigfile) < 0) + G_fatal_error(_("<%s> is an illegal file name"), name_sigfile); /* Input SVM parameters */ /* TODO: Implement parameter checking duplicating svm_check_parameter() to generate translatable errors */ @@ -338,18 +335,18 @@ int main(int argc, char *argv[]) /* Get bands */ if (opt_subgroup->answer) { if (!I_get_subgroup_ref2 - (name_group, opt_subgroup->answer, mapset_group, &band_ref)) { + (name_group, opt_subgroup->answer, mapset_group, &group_ref)) { G_fatal_error(_("There was an error reading subgroup <%s> in group <%s@%s>"), opt_subgroup->answer, name_group, mapset_group); } } else { - if (!I_get_group_ref2(name_group, mapset_group, &band_ref)) { + if (!I_get_group_ref2(name_group, mapset_group, &group_ref)) { G_fatal_error(_("There was an error reading group <%s@%s>"), name_group, mapset_group); } } - if (band_ref.nfiles <= 0) { + if (group_ref.nfiles <= 0) { if (opt_subgroup->answer) G_fatal_error(_("Subgroup <%s> in group <%s@%s> contains no raster maps."), opt_subgroup->answer, name_group, mapset_group); @@ -357,38 +354,65 @@ int main(int argc, char *argv[]) G_fatal_error(_("Group <%s@%s> contains no raster maps."), name_group, mapset_group); } + bandrefs = G_malloc(group_ref.nfiles * sizeof(char *)); + for (int n = 0; n < group_ref.nfiles; n++) { + bandrefs[n] = + Rast_read_bandref(group_ref.file[n].name, + group_ref.file[n].mapset); + if (!bandrefs[n]) + G_fatal_error(_("Raster map <%s@%s> lacks band reference"), + group_ref.file[n].name, group_ref.file[n].mapset); + } svm_set_print_string_function(&print_func); /* Fill svm_problem struct with training data */ G_message(_("Reading training data")); - fill_problem(name_labels, mapset_labels, band_ref, mapset_group, + fill_problem(name_labels, mapset_labels, group_ref, mapset_group, &problem); /* svm_check_parameter needs filled svm_problem struct thus checking only now */ - G_verbose_message("Checking SVM parameterization"); + G_verbose_message("Checking SVM parametrization"); parameters_error = svm_check_parameter(&problem, ¶meters); if (parameters_error) G_fatal_error(_("SVM parameter validation returned an error: %s\n"), parameters_error); /* Train model. Might take some time. */ - G_message(_("Starting training process")); + G_message(_("Starting training process (it will take some time; " + "no progress is printed, be patient)")); model = svm_train(&problem, ¶meters); /* Write out training results */ - /* TODO: Move to Imagery library? */ G_verbose_message("Writing out trained SVM"); - if (G__make_mapset_element_misc(sigfile_dir, name_sigfile) == 0) - G_fatal_error(_("Failed to create signatures for group <%s>"), - opt_group->answer); - G_file_name_misc(out_file, sigfile_dir, "model", name_sigfile, - G_mapset()); - out_status = svm_save_model(out_file, model); + /* This is a specific case as file is not written by GRASS but + * by libsvm and thus "normal" GRASS lib functions can not be used. */ + I__make_signatures_element(I_SIGFILE_TYPE_LIBSVM); + I__get_signatures_element(sigfile_dir, I_SIGFILE_TYPE_LIBSVM); + /* G_fopen_new_misc should create a directory for later use */ + misc_file = G_fopen_new_misc(sigfile_dir, "version", name_sigfile); + if (!misc_file) + G_fatal_error(_("Unable to write trained model to file '%s'."), + name_sigfile); + fprintf(misc_file, "1\n"); + fclose(misc_file); + + /* Write out SVM values in a signature file */ + G_file_name_misc(out_path, sigfile_dir, "sig", name_sigfile, G_mapset()); + out_status = svm_save_model(out_path, model); if (out_status != 0) { G_fatal_error(_("Unable to write trained model to file '%s'. Error code: %d"), - out_file, out_status); + out_path, out_status); + } + /* Write out band reference info */ + misc_file = G_fopen_new_misc(sigfile_dir, "bandref", name_sigfile); + if (!misc_file) + G_fatal_error(_("Unable to write trained model to file '%s'."), + name_sigfile); + for (int n = 0; n < group_ref.nfiles; n++) { + fprintf(misc_file, "%s\n", bandrefs[n]); } + fclose(misc_file); /* Copy CATs file. Will be used for prediction result maps */ G_verbose_message("Copying category information"); @@ -401,7 +425,7 @@ int main(int argc, char *argv[]) } /* Copy color file. Will be used for prediction result maps */ - G_verbose_message("Copying color information"); + G_verbose_message("Copying colour information"); if (G_find_file2("colr", name_labels, mapset_labels)) { /* Path to training label map colr file */ G_file_name(in_path, "colr", name_labels, mapset_labels); @@ -412,20 +436,20 @@ int main(int argc, char *argv[]) /* History will be appended to a prediction result map history */ G_verbose_message("Writing out history"); - hist_file = G_fopen_new_misc(sigfile_dir, "history", name_sigfile); - if (hist_file != NULL) { + misc_file = G_fopen_new_misc(sigfile_dir, "history", name_sigfile); + if (misc_file != NULL) { G_zero(&history, sizeof(struct History)); /* Rast_command_history performs command wrapping */ Rast_command_history(&history); for (i = 0; i < history.nlines; i++) - fprintf(hist_file, "%s\n", history.lines[i]); - fclose(hist_file); + fprintf(misc_file, "%s\n", history.lines[i]); + fclose(misc_file); } else { G_warning(_("Unable to write history information for <%s>"), name_sigfile); } - G_message(_("Training successfuly complete")); + G_message(_("Training successfully complete")); exit(EXIT_SUCCESS); } diff --git a/imagery/i.svm.train/testsuite/test_i_svm_train.py b/imagery/i.svm.train/testsuite/test_i_svm_train.py new file mode 100644 index 00000000000..3e3a6122900 --- /dev/null +++ b/imagery/i.svm.train/testsuite/test_i_svm_train.py @@ -0,0 +1,188 @@ +""" +Name: i.svm.train input & output tests +Purpose: Validates user input validation code and output generation + +Author: Maris Nartiss +Copyright: (C) 2021 by Maris Nartiss and the GRASS Development Team +Licence: This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. +""" +import os +import unittest +import ctypes + +from grass.script import core as grass +from grass.script import shutil_which +from grass.gunittest.case import TestCase +from grass.gunittest.main import test +from grass.gunittest.gmodules import SimpleModule +from grass.pygrass.gis import Mapset +from grass.pygrass import utils + +from grass.lib.gis import ( + GPATH_MAX, + GNAME_MAX, + G_file_name_misc, +) +from grass.lib.imagery import ( + I_SIGFILE_TYPE_LIBSVM, + I__get_signatures_element, + I_signatures_remove, +) + + +class IOValidationTest(TestCase): + """Test input validation and output generation with i.svm.train""" + + @classmethod + @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + def setUpClass(cls): + cls.tmp_rasts = [] + cls.tmp_groups = [] + cls.tmp_sigs = [] + cls.mapset_name = Mapset().name + # Small region for small testing rasters + cls.use_temp_region() + cls.runModule("g.region", n=1, s=0, e=1, w=0, res=1) + # A raster without a band reference + cls.rast1 = grass.tempname(10) + cls.runModule("r.mapcalc", expression=f"{cls.rast1}=1", quiet=True) + cls.tmp_rasts.append(cls.rast1) + cls.runModule("r.colors", _map=cls.rast1, color="grey", quiet=True) + # A raster with a band reference + cls.rast2 = grass.tempname(10) + cls.runModule("r.mapcalc", expression=f"{cls.rast2}=1", quiet=True) + cls.tmp_rasts.append(cls.rast2) + cls.runModule("r.support", _map=cls.rast2, bandref="GRASS_RND", quiet=True) + cls.rast3 = grass.tempname(10) + cls.runModule("r.mapcalc", expression=f"{cls.rast3}=1", quiet=True) + cls.tmp_rasts.append(cls.rast3) + cls.runModule("r.support", _map=cls.rast3, bandref="GRASS_RND", quiet=True) + # An empty imagery group + cls.group1 = grass.tempname(10) + cls.runModule("i.group", group=cls.group1, _input=(cls.rast1,), quiet=True) + cls.tmp_groups.append(cls.group1) + cls.runModule( + "i.group", flags="r", group=cls.group1, _input=(cls.rast1,), quiet=True + ) + # An imagery group with raster lacking band reference + cls.group2 = grass.tempname(10) + cls.runModule("i.group", group=cls.group2, _input=(cls.rast1,), quiet=True) + cls.tmp_groups.append(cls.group2) + # A good imagery group + cls.group3 = grass.tempname(10) + cls.runModule( + "i.group", group=cls.group3, _input=(cls.rast2, cls.rast3), quiet=True + ) + cls.tmp_groups.append(cls.group3) + + @classmethod + def tearDownClass(cls): + """Remove the temporary region and generated data""" + cls.del_temp_region() + for rast in cls.tmp_rasts: + cls.runModule("g.remove", flags="f", _type="raster", name=rast) + for group in cls.tmp_groups: + cls.runModule("g.remove", flags="f", _type="group", name=group) + for sig in cls.tmp_sigs: + I_signatures_remove(I_SIGFILE_TYPE_LIBSVM, sig) + + @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + def test_empty_group(self): + """Empty imagery group handling""" + sigfile = grass.tempname(10) + isvm = SimpleModule( + "i.svm.train", + group=self.group1, + _input=self.rast1, + signaturefile=sigfile, + quiet=True, + ) + self.assertModuleFail(isvm) + self.assertTrue(isvm.outputs.stderr) + self.assertIn(self.group1, isvm.outputs.stderr) + + @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + def test_rast_no_bandref(self): + """One of imagery group rasters lacks band reference""" + sigfile = grass.tempname(10) + isvm = SimpleModule( + "i.svm.train", + group=self.group2, + _input=self.rast1, + signaturefile=sigfile, + quiet=True, + ) + self.assertModuleFail(isvm) + self.assertTrue(isvm.outputs.stderr) + self.assertIn(self.rast1, isvm.outputs.stderr) + + @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + def test_wrong_sigfile_mapset(self): + """Attempt to use FQ signature file name with not current mapset""" + sigfile = grass.tempname(10) + mapset = grass.tempname(10) + isvm = SimpleModule( + "i.svm.train", + group=self.group3, + _input=self.rast1, + signaturefile=f"{sigfile}@{mapset}", + quiet=True, + ) + self.assertModuleFail(isvm) + self.assertTrue(isvm.outputs.stderr) + self.assertIn(mapset, isvm.outputs.stderr) + + @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + def test_wrong_svm_param(self): + """Attempt to use invalid SVM parametres""" + sigfile = grass.tempname(10) + isvm = SimpleModule( + "i.svm.train", + group=self.group3, + _input=self.rast1, + signaturefile=sigfile, + eps=-1, + quiet=True, + ) + self.assertModuleFail(isvm) + self.assertTrue(isvm.outputs.stderr) + self.assertIn("eps", isvm.outputs.stderr) + + @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + def test_creation_of_misc_files(self): + """Validate creation of category, history and colour files""" + sigfile = grass.tempname(10) + csigdir = ctypes.create_string_buffer(GNAME_MAX) + I__get_signatures_element(csigdir, I_SIGFILE_TYPE_LIBSVM) + sigdir = utils.decode(csigdir.value) + isvm = SimpleModule( + "i.svm.train", + group=self.group3, + _input=self.rast1, + signaturefile=sigfile, + quiet=True, + ) + self.assertModule(isvm) + self.tmp_sigs.append(sigfile) + cpath = ctypes.create_string_buffer(GPATH_MAX) + G_file_name_misc(cpath, sigdir, "version", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "sig", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "cats", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "colr", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "history", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + + +if __name__ == "__main__": + test() From 985de22ab48e98da72f396421cfc4501325bbdaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 10 Sep 2021 12:50:17 +0300 Subject: [PATCH 016/123] i.svm: move from element to dir in library calls --- lib/imagery/manage_signatures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/imagery/manage_signatures.c b/lib/imagery/manage_signatures.c index d260f2df3ba..3fbbb29cd77 100644 --- a/lib/imagery/manage_signatures.c +++ b/lib/imagery/manage_signatures.c @@ -35,7 +35,7 @@ void I_get_signatures_dir(char *dir, I_SIGFILE_TYPE type) sprintf(dir, "signatures%csigset", HOST_DIRSEP); } else if (type == I_SIGFILE_TYPE_LIBSVM) { - sprintf(element, "signatures%clibsvm", HOST_DIRSEP); + sprintf(dir, "signatures%clibsvm", HOST_DIRSEP); } else { G_fatal_error("Programming error: unknown signature file type"); From 5eb422af35bf35519d88f3c6fa92bd8036a02d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 10 Sep 2021 12:50:46 +0300 Subject: [PATCH 017/123] i.svm: updated version of configure --- configure | 1663 +++++++++++++++++++++++++++++------------------------ 1 file changed, 908 insertions(+), 755 deletions(-) diff --git a/configure b/configure index 6566a7639f2..56eeca3e6e8 100755 --- a/configure +++ b/configure @@ -48,6 +48,8 @@ ac_help="$ac_help --with-blas support BLAS functionality (default: no)" ac_help="$ac_help --with-lapack support LAPACK functionality (default: no)" +ac_help="$ac_help + --with-libsvm support libsvm functionality (default: no)" ac_help="$ac_help --with-cairo support Cairo functionality (default: yes)" ac_help="$ac_help @@ -178,6 +180,11 @@ ac_help="$ac_help LAPACK include files are in DIRS" ac_help="$ac_help --with-lapack-libs=DIRS LAPACK library files are in DIRS" +ac_help="$ac_help + --with-libsvm-includes=DIRS + libsvm include files are in DIRS" +ac_help="$ac_help + --with-libsvm-libs=DIRS libsvm library files are in DIRS" ac_help="$ac_help --with-cairo-includes=DIRS cairo include files are in DIRS" @@ -762,7 +769,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:766: checking host system type" >&5 +echo "configure:773: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -785,7 +792,7 @@ echo "$ac_t""$host" 1>&6 # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:789: checking for $ac_word" >&5 +echo "configure:796: checking for $ac_word" >&5 if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. @@ -812,7 +819,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:816: checking for $ac_word" >&5 +echo "configure:823: checking for $ac_word" >&5 if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. @@ -860,7 +867,7 @@ fi # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:864: checking for $ac_word" >&5 +echo "configure:871: checking for $ac_word" >&5 if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. @@ -889,7 +896,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:893: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:900: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -900,12 +907,12 @@ cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF -#line 904 "configure" +#line 911 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:909: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:916: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -931,19 +938,19 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:935: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:942: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:940: checking whether we are using GNU C" >&5 +echo "configure:947: checking whether we are using GNU C" >&5 cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:954: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -961,7 +968,7 @@ ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:965: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:972: checking whether ${CC-cc} accepts -g" >&5 echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then @@ -990,10 +997,10 @@ else fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:994: checking for Cygwin environment" >&5 +echo "configure:1001: checking for Cygwin environment" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1015: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else @@ -1020,17 +1027,17 @@ echo "$ac_t""$ac_cv_cygwin" 1>&6 CYGWIN= test "$ac_cv_cygwin" = yes && CYGWIN=yes echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 -echo "configure:1024: checking for mingw32 environment" >&5 +echo "configure:1031: checking for mingw32 environment" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1041: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mingw32=yes else @@ -1048,7 +1055,7 @@ test "$ac_cv_mingw32" = yes && MINGW32=yes echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:1052: checking for executable suffix" >&5 +echo "configure:1059: checking for executable suffix" >&5 if test "$CYGWIN" = yes || test "$MINGW32" = yes; then ac_cv_exeext=.exe @@ -1080,23 +1087,23 @@ PKG_CONFIG=${PKG_CONFIG-pkg-config} IEEEFLAG= echo $ac_n "checking for full floating-point support""... $ac_c" 1>&6 -echo "configure:1084: checking for full floating-point support" >&5 +echo "configure:1091: checking for full floating-point support" >&5 if test "$cross_compiling" = yes; then echo "$ac_t""unknown (cross-compiling)" 1>&6 echo $ac_n "checking whether "cc -mieee" works""... $ac_c" 1>&6 -echo "configure:1089: checking whether "cc -mieee" works" >&5 +echo "configure:1096: checking whether "cc -mieee" works" >&5 ac_save_cflags=${CFLAGS} CFLAGS="$CFLAGS -mieee" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1107: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* echo "$ac_t""yes" 1>&6 IEEEFLAG="-mieee" @@ -1112,7 +1119,7 @@ CFLAGS=${ac_save_cflags} else cat > conftest.$ac_ext < @@ -1126,7 +1133,7 @@ int main(void) { } EOF -if { (eval echo configure:1130: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1137: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then echo "$ac_t""yes" 1>&6 @@ -1139,14 +1146,14 @@ else CFLAGS=-mieee echo $ac_n "checking for full floating-point support with -mieee""... $ac_c" 1>&6 -echo "configure:1143: checking for full floating-point support with -mieee" >&5 +echo "configure:1150: checking for full floating-point support with -mieee" >&5 if test "$cross_compiling" = yes; then echo "$ac_t""unknown (cross-compiling)" 1>&6 { echo "configure: error: *** INTERNAL CONFIGURE ERROR" 1>&2; exit 1; } else cat > conftest.$ac_ext < @@ -1160,7 +1167,7 @@ int main(void) { } EOF -if { (eval echo configure:1164: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1171: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then echo "$ac_t""yes" 1>&6 IEEEFLAG="-mieee" @@ -1197,7 +1204,7 @@ fi # Extract the first word of "pwd", so it can be a program name with args. set dummy pwd; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1201: checking for $ac_word" >&5 +echo "configure:1208: checking for $ac_word" >&5 case "$pwd" in /*) @@ -1235,7 +1242,7 @@ else fi echo $ac_n "checking for source directory""... $ac_c" 1>&6 -echo "configure:1239: checking for source directory" >&5 +echo "configure:1246: checking for source directory" >&5 if test -z "$srcdir" ; then SRCDIR=`$pwd` @@ -1246,7 +1253,7 @@ fi echo "$ac_t"""$SRCDIR"" 1>&6 echo $ac_n "checking for build directory""... $ac_c" 1>&6 -echo "configure:1250: checking for build directory" >&5 +echo "configure:1257: checking for build directory" >&5 DSTDIR=`$pwd` WINDSTDIR=`$winpwd` @@ -1318,7 +1325,7 @@ GRASS_HEADERS_GIT_DATE=`date -u +%FT%T%z | sed 's/\(..\)$/:\1/'` # Extract the first word of "git", so it can be a program name with args. set dummy git; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1322: checking for $ac_word" >&5 +echo "configure:1329: checking for $ac_word" >&5 case "$GIT" in /*) @@ -1387,7 +1394,7 @@ fi echo $ac_n "checking for MacOSX App""... $ac_c" 1>&6 -echo "configure:1391: checking for MacOSX App" >&5 +echo "configure:1398: checking for MacOSX App" >&5 case "$enable_macosx_app" in yes) MACOSX_APP=1 ;; no) MACOSX_APP= ;; @@ -1399,7 +1406,7 @@ echo "$ac_t"""$enable_macosx_app"" 1>&6 # Check for MacOSX archs echo $ac_n "checking for MacOSX architectures""... $ac_c" 1>&6 -echo "configure:1403: checking for MacOSX architectures" >&5 +echo "configure:1410: checking for MacOSX architectures" >&5 MACOSX_ARCHS= @@ -1428,7 +1435,7 @@ fi # Check for MacOSX SDK echo $ac_n "checking for MacOSX SDK""... $ac_c" 1>&6 -echo "configure:1432: checking for MacOSX SDK" >&5 +echo "configure:1439: checking for MacOSX SDK" >&5 MACOSX_SDK= @@ -1438,7 +1445,7 @@ else ac_safe=`echo "$with_macosx_sdk/SDKSettings.plist" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $with_macosx_sdk/SDKSettings.plist""... $ac_c" 1>&6 -echo "configure:1442: checking for $with_macosx_sdk/SDKSettings.plist" >&5 +echo "configure:1449: checking for $with_macosx_sdk/SDKSettings.plist" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: Cannot check for file existence when cross compiling" 1>&2; exit 1; } @@ -1482,7 +1489,7 @@ fi echo $ac_n "checking how to build libraries""... $ac_c" 1>&6 -echo "configure:1486: checking how to build libraries" >&5 +echo "configure:1493: checking how to build libraries" >&5 # Check whether --enable-shared or --disable-shared was given. if test "${enable_shared+set}" = set; then enableval="$enable_shared" @@ -1831,6 +1838,16 @@ fi +# Check whether --with-libsvm or --without-libsvm was given. +if test "${with_libsvm+set}" = set; then + withval="$with_libsvm" + : +else + with_libsvm=no +fi + + + # Check whether --with-cairo or --without-cairo was given. if test "${with_cairo+set}" = set; then withval="$with_cairo" @@ -2256,6 +2273,23 @@ fi +# Check whether --with-libsvm-includes or --without-libsvm-includes was given. +if test "${with_libsvm_includes+set}" = set; then + withval="$with_libsvm_includes" + : +fi + + + +# Check whether --with-libsvm-libs or --without-libsvm-libs was given. +if test "${with_libsvm_libs+set}" = set; then + withval="$with_libsvm_libs" + : +fi + + + + # Check whether --with-cairo-includes or --without-cairo-includes was given. if test "${with_cairo_includes+set}" = set; then withval="$with_cairo_includes" @@ -2417,7 +2451,7 @@ fi # Done checking fortran echo $ac_n "checking for additional include dirs""... $ac_c" 1>&6 -echo "configure:2421: checking for additional include dirs" >&5 +echo "configure:2455: checking for additional include dirs" >&5 case "$with_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to list --with-includes." 1>&2; exit 1; } @@ -2440,7 +2474,7 @@ fi # With libs option echo $ac_n "checking for additional library dirs""... $ac_c" 1>&6 -echo "configure:2444: checking for additional library dirs" >&5 +echo "configure:2478: checking for additional library dirs" >&5 case "$with_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory list to --with-libs." 1>&2; exit 1; } @@ -2474,7 +2508,7 @@ fi # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:2478: checking for a BSD compatible install" >&5 +echo "configure:2512: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" @@ -2527,7 +2561,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Extract the first word of "flex", so it can be a program name with args. set dummy flex; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2531: checking for $ac_word" >&5 +echo "configure:2565: checking for $ac_word" >&5 if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. @@ -2558,13 +2592,13 @@ then *) ac_lib=l ;; esac echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6 -echo "configure:2562: checking for yywrap in -l$ac_lib" >&5 +echo "configure:2596: checking for yywrap in -l$ac_lib" >&5 ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-l$ac_lib $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2613: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2600,7 +2634,7 @@ if test "$LEX" = "lex"; then # Extract the first word of "lex", so it can be a program name with args. set dummy lex; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2604: checking for $ac_word" >&5 +echo "configure:2638: checking for $ac_word" >&5 case "$LEXPATH" in /*) @@ -2640,7 +2674,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2644: checking for $ac_word" >&5 +echo "configure:2678: checking for $ac_word" >&5 if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. @@ -2671,7 +2705,7 @@ if test "$YACC" = "yacc"; then # Extract the first word of "yacc", so it can be a program name with args. set dummy yacc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2675: checking for $ac_word" >&5 +echo "configure:2709: checking for $ac_word" >&5 case "$YACCPATH" in /*) @@ -2709,7 +2743,7 @@ fi # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2713: checking for $ac_word" >&5 +echo "configure:2747: checking for $ac_word" >&5 if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. @@ -2738,7 +2772,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2742: checking for $ac_word" >&5 +echo "configure:2776: checking for $ac_word" >&5 if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. @@ -2769,7 +2803,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2773: checking for $ac_word" >&5 +echo "configure:2807: checking for $ac_word" >&5 if test -n "$ENV"; then ac_cv_prog_ENV="$ENV" # Let the user override the test. @@ -2798,7 +2832,7 @@ done # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2802: checking for $ac_word" >&5 +echo "configure:2836: checking for $ac_word" >&5 case "$PERL" in /*) @@ -2829,7 +2863,7 @@ else fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:2833: checking how to run the C preprocessor" >&5 +echo "configure:2867: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -2842,13 +2876,13 @@ if test -z "$CPP"; then # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2852: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2886: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2859,13 +2893,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2869: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2903: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2876,13 +2910,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2886: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2920: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2906,10 +2940,10 @@ fi echo "$ac_t""$CPP" 1>&6 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:2910: checking for ANSI C header files" >&5 +echo "configure:2944: checking for ANSI C header files" >&5 cat > conftest.$ac_ext < #include @@ -2917,7 +2951,7 @@ cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2921: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2955: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -2934,7 +2968,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -2952,7 +2986,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -2973,7 +3007,7 @@ if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') @@ -2984,7 +3018,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -if { (eval echo configure:2988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3022: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else @@ -3011,15 +3045,15 @@ for ac_hdr in limits.h termio.h termios.h unistd.h values.h f2c.h g2c.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:3015: checking for $ac_hdr" >&5 +echo "configure:3049: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3023: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3057: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -3048,15 +3082,15 @@ for ac_hdr in sys/ioctl.h sys/mtio.h sys/resource.h sys/time.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:3052: checking for $ac_hdr" >&5 +echo "configure:3086: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3060: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3094: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -3085,15 +3119,15 @@ for ac_hdr in sys/timeb.h sys/types.h sys/utsname.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:3089: checking for $ac_hdr" >&5 +echo "configure:3123: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3097: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3131: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -3122,15 +3156,15 @@ for ac_hdr in libintl.h iconv.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:3126: checking for $ac_hdr" >&5 +echo "configure:3160: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3134: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3168: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -3159,15 +3193,15 @@ for ac_hdr in langinfo.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:3163: checking for $ac_hdr" >&5 +echo "configure:3197: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3171: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3205: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -3193,10 +3227,10 @@ fi done echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 -echo "configure:3197: checking whether time.h and sys/time.h may both be included" >&5 +echo "configure:3231: checking whether time.h and sys/time.h may both be included" >&5 cat > conftest.$ac_ext < #include @@ -3205,7 +3239,7 @@ int main() { struct tm *tp; ; return 0; } EOF -if { (eval echo configure:3209: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3243: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else @@ -3225,10 +3259,10 @@ EOF fi echo $ac_n "checking for off_t""... $ac_c" 1>&6 -echo "configure:3229: checking for off_t" >&5 +echo "configure:3263: checking for off_t" >&5 cat > conftest.$ac_ext < #if STDC_HEADERS @@ -3255,10 +3289,10 @@ EOF fi echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:3259: checking for uid_t in sys/types.h" >&5 +echo "configure:3293: checking for uid_t in sys/types.h" >&5 cat > conftest.$ac_ext < EOF @@ -3286,10 +3320,10 @@ EOF fi echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 -echo "configure:3290: checking return type of signal handlers" >&5 +echo "configure:3324: checking return type of signal handlers" >&5 cat > conftest.$ac_ext < #include @@ -3306,7 +3340,7 @@ int main() { int i; ; return 0; } EOF -if { (eval echo configure:3310: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3344: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_type_signal=void else @@ -3324,10 +3358,10 @@ EOF echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:3328: checking for Cygwin environment" >&5 +echo "configure:3362: checking for Cygwin environment" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3376: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else @@ -3356,10 +3390,10 @@ test "$ac_cv_cygwin" = yes && CYGWIN=yes for ac_func in ftime gethostname gettimeofday lseek nice time uname do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3360: checking for $ac_func" >&5 +echo "configure:3394: checking for $ac_func" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3420: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3408,10 +3442,10 @@ done for ac_func in seteuid setpriority setreuid setruid do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3412: checking for $ac_func" >&5 +echo "configure:3446: checking for $ac_func" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3472: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3460,10 +3494,10 @@ done for ac_func in drand48 do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3464: checking for $ac_func" >&5 +echo "configure:3498: checking for $ac_func" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3524: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3512,10 +3546,10 @@ done for ac_func in putenv setenv do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3516: checking for $ac_func" >&5 +echo "configure:3550: checking for $ac_func" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3576: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3564,10 +3598,10 @@ done for ac_func in nanosleep do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3568: checking for $ac_func" >&5 +echo "configure:3602: checking for $ac_func" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3628: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3615,13 +3649,13 @@ done if test "$cross_compiling" != "yes" ; then echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6 -echo "configure:3619: checking whether setpgrp takes no argument" >&5 +echo "configure:3653: checking whether setpgrp takes no argument" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3679: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_setpgrp_void=no else @@ -3669,16 +3703,16 @@ CROSS_COMPILING=1 fi echo $ac_n "checking for long long int""... $ac_c" 1>&6 -echo "configure:3673: checking for long long int" >&5 +echo "configure:3707: checking for long long int" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3716: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* echo "$ac_t""yes" 1>&6 @@ -3698,16 +3732,16 @@ fi rm -f conftest* echo $ac_n "checking for int64_t""... $ac_c" 1>&6 -echo "configure:3702: checking for int64_t" >&5 +echo "configure:3736: checking for int64_t" >&5 cat > conftest.$ac_ext < int main() { int64_t x; ; return 0; } EOF -if { (eval echo configure:3711: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3745: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* echo "$ac_t""yes" 1>&6 @@ -3727,7 +3761,7 @@ fi rm -f conftest* echo $ac_n "checking for W11""... $ac_c" 1>&6 -echo "configure:3731: checking for W11" >&5 +echo "configure:3765: checking for W11" >&5 case "$enable_w11" in yes|no) echo "$ac_t"""$enable_w11"" 1>&6 ;; *) { echo "configure: error: *** You must answer yes or no." 1>&2; exit 1; } ;; @@ -3755,7 +3789,7 @@ else # Uses ac_ vars as temps to allow command line to override cache and checks. # --without-x overrides everything else, but does not touch the cache. echo $ac_n "checking for X""... $ac_c" 1>&6 -echo "configure:3759: checking for X" >&5 +echo "configure:3793: checking for X" >&5 # Check whether --with-x or --without-x was given. if test "${with_x+set}" = set; then @@ -3815,12 +3849,12 @@ if test "$ac_x_includes" = NO; then # First, try using that file with no special directory specified. cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3824: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3858: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -3889,14 +3923,14 @@ if test "$ac_x_libraries" = NO; then ac_save_LIBS="$LIBS" LIBS="-l$x_direct_test_library $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3934: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* LIBS="$ac_save_LIBS" # We can link X programs with no special library path. @@ -4001,17 +4035,17 @@ else case "`(uname -sr) 2>/dev/null`" in "SunOS 5"*) echo $ac_n "checking whether -R must be followed by a space""... $ac_c" 1>&6 -echo "configure:4005: checking whether -R must be followed by a space" >&5 +echo "configure:4039: checking whether -R must be followed by a space" >&5 ac_xsave_LIBS="$LIBS"; LIBS="$LIBS -R$x_libraries" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4049: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_R_nospace=yes else @@ -4027,14 +4061,14 @@ rm -f conftest* else LIBS="$ac_xsave_LIBS -R $x_libraries" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4072: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_R_space=yes else @@ -4066,13 +4100,13 @@ rm -f conftest* # libraries were built with DECnet support. And karl@cs.umb.edu says # the Alpha needs dnet_stub (dnet does not exist). echo $ac_n "checking for dnet_ntoa in -ldnet""... $ac_c" 1>&6 -echo "configure:4070: checking for dnet_ntoa in -ldnet" >&5 +echo "configure:4104: checking for dnet_ntoa in -ldnet" >&5 ac_lib_var=`echo dnet'_'dnet_ntoa | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ldnet $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4121: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4104,13 +4138,13 @@ fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then echo $ac_n "checking for dnet_ntoa in -ldnet_stub""... $ac_c" 1>&6 -echo "configure:4108: checking for dnet_ntoa in -ldnet_stub" >&5 +echo "configure:4142: checking for dnet_ntoa in -ldnet_stub" >&5 ac_lib_var=`echo dnet_stub'_'dnet_ntoa | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ldnet_stub $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4159: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4149,10 +4183,10 @@ fi # The nsl library prevents programs from opening the X display # on Irix 5.2, according to dickey@clark.net. echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 -echo "configure:4153: checking for gethostbyname" >&5 +echo "configure:4187: checking for gethostbyname" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4213: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname=yes" else @@ -4195,13 +4229,13 @@ fi if test $ac_cv_func_gethostbyname = no; then echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6 -echo "configure:4199: checking for gethostbyname in -lnsl" >&5 +echo "configure:4233: checking for gethostbyname in -lnsl" >&5 ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4250: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4241,10 +4275,10 @@ fi # -lsocket must be given before -lnsl if both are needed. # We assume that if connect needs -lnsl, so does gethostbyname. echo $ac_n "checking for connect""... $ac_c" 1>&6 -echo "configure:4245: checking for connect" >&5 +echo "configure:4279: checking for connect" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4305: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_connect=yes" else @@ -4287,13 +4321,13 @@ fi if test $ac_cv_func_connect = no; then echo $ac_n "checking for connect in -lsocket""... $ac_c" 1>&6 -echo "configure:4291: checking for connect in -lsocket" >&5 +echo "configure:4325: checking for connect in -lsocket" >&5 ac_lib_var=`echo socket'_'connect | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lsocket $X_EXTRA_LIBS $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4342: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4327,10 +4361,10 @@ fi # gomez@mi.uni-erlangen.de says -lposix is necessary on A/UX. echo $ac_n "checking for remove""... $ac_c" 1>&6 -echo "configure:4331: checking for remove" >&5 +echo "configure:4365: checking for remove" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4391: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_remove=yes" else @@ -4373,13 +4407,13 @@ fi if test $ac_cv_func_remove = no; then echo $ac_n "checking for remove in -lposix""... $ac_c" 1>&6 -echo "configure:4377: checking for remove in -lposix" >&5 +echo "configure:4411: checking for remove in -lposix" >&5 ac_lib_var=`echo posix'_'remove | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lposix $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4428: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4413,10 +4447,10 @@ fi # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. echo $ac_n "checking for shmat""... $ac_c" 1>&6 -echo "configure:4417: checking for shmat" >&5 +echo "configure:4451: checking for shmat" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4477: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_shmat=yes" else @@ -4459,13 +4493,13 @@ fi if test $ac_cv_func_shmat = no; then echo $ac_n "checking for shmat in -lipc""... $ac_c" 1>&6 -echo "configure:4463: checking for shmat in -lipc" >&5 +echo "configure:4497: checking for shmat in -lipc" >&5 ac_lib_var=`echo ipc'_'shmat | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lipc $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4514: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4508,13 +4542,13 @@ fi # libraries we check for below, so use a different variable. # --interran@uluru.Stanford.EDU, kb@cs.umb.edu. echo $ac_n "checking for IceConnectionNumber in -lICE""... $ac_c" 1>&6 -echo "configure:4512: checking for IceConnectionNumber in -lICE" >&5 +echo "configure:4546: checking for IceConnectionNumber in -lICE" >&5 ac_lib_var=`echo ICE'_'IceConnectionNumber | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lICE $X_EXTRA_LIBS $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4563: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4565,12 +4599,12 @@ ac_save_libs="$LIBS" LIBS="" echo $ac_n "checking for library containing cuserid""... $ac_c" 1>&6 -echo "configure:4569: checking for library containing cuserid" >&5 +echo "configure:4603: checking for library containing cuserid" >&5 ac_func_search_save_LIBS="$LIBS" ac_cv_search_cuserid="no" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4619: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_cuserid="none required" else @@ -4592,7 +4626,7 @@ rm -f conftest* test "$ac_cv_search_cuserid" = "no" && for i in compat; do LIBS="-l$i $ac_func_search_save_LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4641: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_cuserid="-l$i" break @@ -4629,10 +4663,10 @@ LIBS="$ac_save_libs" for ac_func in asprintf do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:4633: checking for $ac_func" >&5 +echo "configure:4667: checking for $ac_func" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4693: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -4682,10 +4716,10 @@ done # Test if mathlib needs -lm flag or is included with libc echo $ac_n "checking for atan""... $ac_c" 1>&6 -echo "configure:4686: checking for atan" >&5 +echo "configure:4720: checking for atan" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4746: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_atan=yes" else @@ -4726,13 +4760,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for atan in -lm""... $ac_c" 1>&6 -echo "configure:4730: checking for atan in -lm" >&5 +echo "configure:4764: checking for atan in -lm" >&5 ac_lib_var=`echo m'_'atan | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lm $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4781: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4770,10 +4804,10 @@ fi echo $ac_n "checking for dlsym""... $ac_c" 1>&6 -echo "configure:4774: checking for dlsym" >&5 +echo "configure:4808: checking for dlsym" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4834: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_dlsym=yes" else @@ -4814,13 +4848,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dlsym in -ldl""... $ac_c" 1>&6 -echo "configure:4818: checking for dlsym in -ldl" >&5 +echo "configure:4852: checking for dlsym in -ldl" >&5 ac_lib_var=`echo dl'_'dlsym | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4869: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4858,10 +4892,10 @@ fi echo $ac_n "checking for iconv""... $ac_c" 1>&6 -echo "configure:4862: checking for iconv" >&5 +echo "configure:4896: checking for iconv" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4922: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_iconv=yes" else @@ -4902,13 +4936,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for iconv in -liconv""... $ac_c" 1>&6 -echo "configure:4906: checking for iconv in -liconv" >&5 +echo "configure:4940: checking for iconv in -liconv" >&5 ac_lib_var=`echo iconv'_'iconv | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-liconv $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4957: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4938,13 +4972,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for iconv in -lgiconv""... $ac_c" 1>&6 -echo "configure:4942: checking for iconv in -lgiconv" >&5 +echo "configure:4976: checking for iconv in -lgiconv" >&5 ac_lib_var=`echo giconv'_'iconv | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lgiconv $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4993: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4974,10 +5008,10 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for libiconv""... $ac_c" 1>&6 -echo "configure:4978: checking for libiconv" >&5 +echo "configure:5012: checking for libiconv" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5038: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_libiconv=yes" else @@ -5018,13 +5052,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for libiconv in -liconv""... $ac_c" 1>&6 -echo "configure:5022: checking for libiconv in -liconv" >&5 +echo "configure:5056: checking for libiconv in -liconv" >&5 ac_lib_var=`echo iconv'_'libiconv | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-liconv $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5073: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -5054,13 +5088,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for libiconv in -lgiconv""... $ac_c" 1>&6 -echo "configure:5058: checking for libiconv in -lgiconv" >&5 +echo "configure:5092: checking for libiconv in -lgiconv" >&5 ac_lib_var=`echo giconv'_'libiconv | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lgiconv $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5109: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -5108,10 +5142,10 @@ fi have_socket=1 echo $ac_n "checking for socket""... $ac_c" 1>&6 -echo "configure:5112: checking for socket" >&5 +echo "configure:5146: checking for socket" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5172: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_socket=yes" else @@ -5152,13 +5186,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 -echo "configure:5156: checking for socket in -lsocket" >&5 +echo "configure:5190: checking for socket in -lsocket" >&5 ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5207: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -5217,7 +5251,7 @@ ZLIB= echo $ac_n "checking for location of zlib includes""... $ac_c" 1>&6 -echo "configure:5221: checking for location of zlib includes" >&5 +echo "configure:5255: checking for location of zlib includes" >&5 case "$with_zlib_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-zlib-includes." 1>&2; exit 1; } @@ -5243,15 +5277,15 @@ for ac_hdr in zlib.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:5247: checking for $ac_hdr" >&5 +echo "configure:5281: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:5255: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:5289: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -5285,7 +5319,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of zlib library""... $ac_c" 1>&6 -echo "configure:5289: checking for location of zlib library" >&5 +echo "configure:5323: checking for location of zlib library" >&5 case "$with_zlib_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-zlib-libs." 1>&2; exit 1; } @@ -5310,13 +5344,13 @@ LDFLAGS="$ZLIBLIBPATH $LDFLAGS" echo $ac_n "checking for deflate in -lz""... $ac_c" 1>&6 -echo "configure:5314: checking for deflate in -lz" >&5 +echo "configure:5348: checking for deflate in -lz" >&5 ac_lib_var=`echo z'_'deflate | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lz $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5365: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -5373,7 +5407,7 @@ BZIP2LIB= echo $ac_n "checking whether to use bzlib""... $ac_c" 1>&6 -echo "configure:5377: checking whether to use bzlib" >&5 +echo "configure:5411: checking whether to use bzlib" >&5 echo "$ac_t"""$with_bzlib"" 1>&6 case "$with_bzlib" in "no") USE_BZIP2= ;; @@ -5389,7 +5423,7 @@ if test -n "$USE_BZIP2"; then echo $ac_n "checking for location of bzlib includes""... $ac_c" 1>&6 -echo "configure:5393: checking for location of bzlib includes" >&5 +echo "configure:5427: checking for location of bzlib includes" >&5 case "$with_bzlib_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-bzlib-includes." 1>&2; exit 1; } @@ -5415,15 +5449,15 @@ for ac_hdr in bzlib.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:5419: checking for $ac_hdr" >&5 +echo "configure:5453: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:5427: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:5461: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -5457,7 +5491,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of bzlib library""... $ac_c" 1>&6 -echo "configure:5461: checking for location of bzlib library" >&5 +echo "configure:5495: checking for location of bzlib library" >&5 case "$with_bzlib_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-bzlib-libs." 1>&2; exit 1; } @@ -5482,13 +5516,13 @@ LDFLAGS="$BZIP2LIBPATH $LDFLAGS" echo $ac_n "checking for BZ2_bzBuffToBuffCompress in -lbz2""... $ac_c" 1>&6 -echo "configure:5486: checking for BZ2_bzBuffToBuffCompress in -lbz2" >&5 +echo "configure:5520: checking for BZ2_bzBuffToBuffCompress in -lbz2" >&5 ac_lib_var=`echo bz2'_'BZ2_bzBuffToBuffCompress | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lbz2 $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5537: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -5547,7 +5581,7 @@ ZSTDLIB= echo $ac_n "checking whether to use zstd""... $ac_c" 1>&6 -echo "configure:5551: checking whether to use zstd" >&5 +echo "configure:5585: checking whether to use zstd" >&5 echo "$ac_t"""$with_zstd"" 1>&6 case "$with_zstd" in "no") USE_ZSTD= ;; @@ -5563,7 +5597,7 @@ if test -n "$USE_ZSTD"; then echo $ac_n "checking for location of zstd includes""... $ac_c" 1>&6 -echo "configure:5567: checking for location of zstd includes" >&5 +echo "configure:5601: checking for location of zstd includes" >&5 case "$with_zstd_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-zstd-includes." 1>&2; exit 1; } @@ -5588,15 +5622,15 @@ for ac_hdr in zstd.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:5592: checking for $ac_hdr" >&5 +echo "configure:5626: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:5600: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:5634: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -5630,7 +5664,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of zstd library""... $ac_c" 1>&6 -echo "configure:5634: checking for location of zstd library" >&5 +echo "configure:5668: checking for location of zstd library" >&5 case "$with_zstd_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-zstd-libs." 1>&2; exit 1; } @@ -5655,13 +5689,13 @@ LDFLAGS="$ZSTDLIBPATH $LDFLAGS" echo $ac_n "checking for ZSTD_compress in -lzstd""... $ac_c" 1>&6 -echo "configure:5659: checking for ZSTD_compress in -lzstd" >&5 +echo "configure:5693: checking for ZSTD_compress in -lzstd" >&5 ac_lib_var=`echo zstd'_'ZSTD_compress | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lzstd $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5710: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -5724,7 +5758,7 @@ PROJMAJOR=4 echo $ac_n "checking for location of External PROJ includes""... $ac_c" 1>&6 -echo "configure:5728: checking for location of External PROJ includes" >&5 +echo "configure:5762: checking for location of External PROJ includes" >&5 case "$with_proj_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-proj-includes." 1>&2; exit 1; } @@ -5751,15 +5785,15 @@ for ac_hdr in proj.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:5755: checking for $ac_hdr" >&5 +echo "configure:5789: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:5763: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:5797: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -5791,7 +5825,7 @@ CPPFLAGS=$ac_save_cppflags if test $PROJ4API = 0 ; then echo $ac_n "checking External PROJ major version""... $ac_c" 1>&6 -echo "configure:5795: checking External PROJ major version" >&5 +echo "configure:5829: checking External PROJ major version" >&5 ac_save_cppflags="$CPPFLAGS" CPPFLAGS="$PROJINC $CPPFLAGS" if test "$cross_compiling" = yes; then @@ -5799,7 +5833,7 @@ if test "$cross_compiling" = yes; then echo "$ac_t""unknown (cross-compiling)" 1>&6 else cat > conftest.$ac_ext < @@ -5811,7 +5845,7 @@ int main(void) { } EOF -if { (eval echo configure:5815: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5849: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then proj_ver_major=`cat conftestdata` echo "$ac_t""$proj_ver_major" 1>&6 @@ -5828,7 +5862,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking External PROJ minor version""... $ac_c" 1>&6 -echo "configure:5832: checking External PROJ minor version" >&5 +echo "configure:5866: checking External PROJ minor version" >&5 ac_save_cppflags="$CPPFLAGS" CPPFLAGS="$PROJINC $CPPFLAGS" if test "$cross_compiling" = yes; then @@ -5836,7 +5870,7 @@ if test "$cross_compiling" = yes; then echo "$ac_t""unknown (cross-compiling)" 1>&6 else cat > conftest.$ac_ext < @@ -5848,7 +5882,7 @@ int main(void) { } EOF -if { (eval echo configure:5852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5886: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then proj_ver_minor=`cat conftestdata` echo "$ac_t""$proj_ver_minor" 1>&6 @@ -5865,7 +5899,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking External PROJ patch version""... $ac_c" 1>&6 -echo "configure:5869: checking External PROJ patch version" >&5 +echo "configure:5903: checking External PROJ patch version" >&5 ac_save_cppflags="$CPPFLAGS" CPPFLAGS="$PROJINC $CPPFLAGS" if test "$cross_compiling" = yes; then @@ -5873,7 +5907,7 @@ if test "$cross_compiling" = yes; then echo "$ac_t""unknown (cross-compiling)" 1>&6 else cat > conftest.$ac_ext < @@ -5885,7 +5919,7 @@ int main(void) { } EOF -if { (eval echo configure:5889: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5923: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then proj_ver_patch=`cat conftestdata` echo "$ac_t""$proj_ver_patch" 1>&6 @@ -5910,7 +5944,7 @@ CPPFLAGS=$ac_save_cppflags else echo $ac_n "checking External PROJ.4 version""... $ac_c" 1>&6 -echo "configure:5914: checking External PROJ.4 version" >&5 +echo "configure:5948: checking External PROJ.4 version" >&5 ac_save_cppflags="$CPPFLAGS" CPPFLAGS="$PROJINC $CPPFLAGS" if test "$cross_compiling" = yes; then @@ -5918,7 +5952,7 @@ if test "$cross_compiling" = yes; then echo "$ac_t""unknown (cross-compiling)" 1>&6 else cat > conftest.$ac_ext < @@ -5930,7 +5964,7 @@ int main(void) { } EOF -if { (eval echo configure:5934: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5968: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then proj_ver=`cat conftestdata` echo "$ac_t""$proj_ver" 1>&6 @@ -5962,7 +5996,7 @@ if test $PROJ4API = 0 ; then echo $ac_n "checking for location of External PROJ library""... $ac_c" 1>&6 -echo "configure:5966: checking for location of External PROJ library" >&5 +echo "configure:6000: checking for location of External PROJ library" >&5 case "$with_proj_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-proj-libs." 1>&2; exit 1; } @@ -5986,13 +6020,13 @@ LDFLAGS="$PROJLIB $LDFLAGS" echo $ac_n "checking for proj_pj_info in -lproj""... $ac_c" 1>&6 -echo "configure:5990: checking for proj_pj_info in -lproj" >&5 +echo "configure:6024: checking for proj_pj_info in -lproj" >&5 ac_lib_var=`echo proj'_'proj_pj_info | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lproj $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6041: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6046,15 +6080,15 @@ for ac_hdr in proj_api.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:6050: checking for $ac_hdr" >&5 +echo "configure:6084: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6058: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6092: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6090,7 +6124,7 @@ CPPFLAGS=$ac_save_cppflags else echo $ac_n "checking External PROJ.4 version""... $ac_c" 1>&6 -echo "configure:6094: checking External PROJ.4 version" >&5 +echo "configure:6128: checking External PROJ.4 version" >&5 ac_save_cppflags="$CPPFLAGS" CPPFLAGS="$PROJINC $CPPFLAGS" if test "$cross_compiling" = yes; then @@ -6098,7 +6132,7 @@ if test "$cross_compiling" = yes; then echo "$ac_t""unknown (cross-compiling)" 1>&6 else cat > conftest.$ac_ext < @@ -6110,7 +6144,7 @@ int main(void) { } EOF -if { (eval echo configure:6114: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:6148: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then proj_ver=`cat conftestdata` echo "$ac_t""$proj_ver" 1>&6 @@ -6135,7 +6169,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of External PROJ.4 library""... $ac_c" 1>&6 -echo "configure:6139: checking for location of External PROJ.4 library" >&5 +echo "configure:6173: checking for location of External PROJ.4 library" >&5 case "$with_proj_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-proj-libs." 1>&2; exit 1; } @@ -6159,13 +6193,13 @@ LDFLAGS="$PROJLIB $LDFLAGS" echo $ac_n "checking for pj_get_def in -lproj""... $ac_c" 1>&6 -echo "configure:6163: checking for pj_get_def in -lproj" >&5 +echo "configure:6197: checking for pj_get_def in -lproj" >&5 ac_lib_var=`echo proj'_'pj_get_def | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lproj $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6214: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6211,7 +6245,7 @@ fi echo $ac_n "checking for location of External PROJ data files""... $ac_c" 1>&6 -echo "configure:6215: checking for location of External PROJ data files" >&5 +echo "configure:6249: checking for location of External PROJ data files" >&5 case "$with_proj_share" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-proj-share." 1>&2; exit 1; } @@ -6237,14 +6271,14 @@ if test `expr ${PROJMAJOR} \< 6` = 1 ; then # LOC_CHECK_SHARE does not work when cross compiling if test "$cross_compiling" = "yes" ; then echo $ac_n "checking for epsg""... $ac_c" 1>&6 -echo "configure:6241: checking for epsg" >&5 +echo "configure:6275: checking for epsg" >&5 echo "$ac_t""unknown (cross-compiling)" 1>&6 else ac_safe=`echo "$PROJSHARE/epsg" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $PROJSHARE/epsg""... $ac_c" 1>&6 -echo "configure:6248: checking for $PROJSHARE/epsg" >&5 +echo "configure:6282: checking for $PROJSHARE/epsg" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: Cannot check for file existence when cross compiling" 1>&2; exit 1; } @@ -6278,7 +6312,7 @@ fi echo $ac_n "checking whether to use regex""... $ac_c" 1>&6 -echo "configure:6282: checking whether to use regex" >&5 +echo "configure:6316: checking whether to use regex" >&5 echo "$ac_t"""$with_regex"" 1>&6 case "$with_regex" in "no") USE_REGEX= ;; @@ -6298,7 +6332,7 @@ if test -n "$USE_REGEX"; then echo $ac_n "checking for location of regex includes""... $ac_c" 1>&6 -echo "configure:6302: checking for location of regex includes" >&5 +echo "configure:6336: checking for location of regex includes" >&5 case "$with_regex_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-regex-includes." 1>&2; exit 1; } @@ -6324,15 +6358,15 @@ for ac_hdr in regex.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:6328: checking for $ac_hdr" >&5 +echo "configure:6362: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6336: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6370: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6366,7 +6400,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of regex library""... $ac_c" 1>&6 -echo "configure:6370: checking for location of regex library" >&5 +echo "configure:6404: checking for location of regex library" >&5 case "$with_regex_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-regex-libs." 1>&2; exit 1; } @@ -6391,10 +6425,10 @@ ac_save_ldflags="$LDFLAGS" LIBS=" $LIBS" LDFLAGS=" $LDFLAGS" echo $ac_n "checking for regcomp""... $ac_c" 1>&6 -echo "configure:6395: checking for regcomp" >&5 +echo "configure:6429: checking for regcomp" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6455: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_regcomp=yes" else @@ -6444,13 +6478,13 @@ LDFLAGS="$REGEXLIBPATH $LDFLAGS" echo $ac_n "checking for regcomp in -lregex""... $ac_c" 1>&6 -echo "configure:6448: checking for regcomp in -lregex" >&5 +echo "configure:6482: checking for regcomp in -lregex" >&5 ac_lib_var=`echo regex'_'regcomp | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lregex $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6499: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6511,7 +6545,7 @@ fi # $USE_REGEX echo $ac_n "checking whether to use Readline""... $ac_c" 1>&6 -echo "configure:6515: checking whether to use Readline" >&5 +echo "configure:6549: checking whether to use Readline" >&5 echo "$ac_t"""$with_readline"" 1>&6 case "$with_readline" in "no") USE_READLINE= ;; @@ -6532,7 +6566,7 @@ if test -n "$USE_READLINE"; then echo $ac_n "checking for location of Readline includes""... $ac_c" 1>&6 -echo "configure:6536: checking for location of Readline includes" >&5 +echo "configure:6570: checking for location of Readline includes" >&5 case "$with_readline_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-readline-includes." 1>&2; exit 1; } @@ -6558,15 +6592,15 @@ for ac_hdr in readline/readline.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:6562: checking for $ac_hdr" >&5 +echo "configure:6596: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6570: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6604: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6602,15 +6636,15 @@ for ac_hdr in readline/history.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:6606: checking for $ac_hdr" >&5 +echo "configure:6640: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6614: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6648: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6644,7 +6678,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of Readline library""... $ac_c" 1>&6 -echo "configure:6648: checking for location of Readline library" >&5 +echo "configure:6682: checking for location of Readline library" >&5 case "$with_readline_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-readline-libs." 1>&2; exit 1; } @@ -6669,13 +6703,13 @@ LDFLAGS="$READLINELIBPATH $LDFLAGS" echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6 -echo "configure:6673: checking for readline in -lreadline" >&5 +echo "configure:6707: checking for readline in -lreadline" >&5 ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lreadline $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6724: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6721,13 +6755,13 @@ LDFLAGS="$READLINELIBPATH $LDFLAGS" echo $ac_n "checking for add_history in -lhistory""... $ac_c" 1>&6 -echo "configure:6725: checking for add_history in -lhistory" >&5 +echo "configure:6759: checking for add_history in -lhistory" >&5 ac_lib_var=`echo history'_'add_history | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lhistory $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6776: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6780,7 +6814,7 @@ fi # $USE_READLINE # GDAL option echo $ac_n "checking whether to use GDAL""... $ac_c" 1>&6 -echo "configure:6784: checking whether to use GDAL" >&5 +echo "configure:6818: checking whether to use GDAL" >&5 GDAL_LIBS= GDAL_CFLAGS= @@ -6798,7 +6832,7 @@ else # Extract the first word of "gdal-config", so it can be a program name with args. set dummy gdal-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:6802: checking for $ac_word" >&5 +echo "configure:6836: checking for $ac_word" >&5 case "$GDAL_CONFIG" in /*) @@ -6853,14 +6887,14 @@ EOF LIBS="$LIBS $GDAL_LIBS" CFLAGS="$CFLAGS $GDAL_CFLAGS" cat > conftest.$ac_ext < int main() { GDALOpen("foo", GA_ReadOnly); ; return 0; } EOF -if { (eval echo configure:6864: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6898: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then : else echo "configure: failed program was:" >&5 @@ -6869,14 +6903,14 @@ else LIBS="$LIBS $GDAL_DEP_LIBS" cat > conftest.$ac_ext < int main() { GDALOpen("foo", GA_ReadOnly); ; return 0; } EOF -if { (eval echo configure:6880: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6914: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* GDAL_LIBS="$GDAL_LIBS $GDAL_DEP_LIBS" else @@ -6908,7 +6942,7 @@ fi # libLAS option echo $ac_n "checking whether to use libLAS""... $ac_c" 1>&6 -echo "configure:6912: checking whether to use libLAS" >&5 +echo "configure:6946: checking whether to use libLAS" >&5 LIBLAS_LIBS= LIBLAS_CFLAGS= @@ -6925,7 +6959,7 @@ else # Extract the first word of "liblas-config", so it can be a program name with args. set dummy liblas-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:6929: checking for $ac_word" >&5 +echo "configure:6963: checking for $ac_word" >&5 case "$LIBLAS_CONFIG" in /*) @@ -6978,15 +7012,15 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:6982: checking for $ac_hdr" >&5 +echo "configure:7016: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6990: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7024: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7012,14 +7046,14 @@ fi done cat > conftest.$ac_ext < int main() { LASReader_Create("foo"); ; return 0; } EOF -if { (eval echo configure:7023: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7057: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then : else echo "configure: failed program was:" >&5 @@ -7027,14 +7061,14 @@ else rm -rf conftest* cat > conftest.$ac_ext < int main() { LASReader_Create("foo"); ; return 0; } EOF -if { (eval echo configure:7038: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7072: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* LAS_LIBS="$LAS_LIBS" else @@ -7067,7 +7101,7 @@ fi # PDAL option echo $ac_n "checking whether to use PDAL""... $ac_c" 1>&6 -echo "configure:7071: checking whether to use PDAL" >&5 +echo "configure:7105: checking whether to use PDAL" >&5 # new and currently used way to switch language to C++ # AC_LANG_PUSH(C++) @@ -7095,7 +7129,7 @@ else # Extract the first word of "pdal-config", so it can be a program name with args. set dummy pdal-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7099: checking for $ac_word" >&5 +echo "configure:7133: checking for $ac_word" >&5 case "$PDAL_CONFIG" in /*) @@ -7145,7 +7179,7 @@ fi CFLAGS="$CFLAGS $PDAL_CFLAGS" CPPFLAGS="$CPPFLAGS $PDAL_CPPFLAGS $PDAL_INC" cat > conftest.$ac_ext < #include @@ -7154,7 +7188,7 @@ int main() { pdal::PointTable table; ; return 0; } EOF -if { (eval echo configure:7158: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7192: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then : else echo "configure: failed program was:" >&5 @@ -7162,7 +7196,7 @@ else rm -rf conftest* cat > conftest.$ac_ext < #include @@ -7171,7 +7205,7 @@ int main() { pdal::PointTable table; ; return 0; } EOF -if { (eval echo configure:7175: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7209: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* PDAL_LIBS="$PDAL_LIBS" else @@ -7221,7 +7255,7 @@ cross_compiling=$ac_cv_prog_cc_cross # NetCDF option echo $ac_n "checking whether to use NetCDF""... $ac_c" 1>&6 -echo "configure:7225: checking whether to use NetCDF" >&5 +echo "configure:7259: checking whether to use NetCDF" >&5 NETCDF_LIBS= NETCDF_CFLAGS= @@ -7238,7 +7272,7 @@ else # Extract the first word of "nc-config", so it can be a program name with args. set dummy nc-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7242: checking for $ac_word" >&5 +echo "configure:7276: checking for $ac_word" >&5 case "$NETCDF_CONFIG" in /*) @@ -7285,14 +7319,14 @@ fi LIBS="$LIBS $NETCDF_LIBS" CFLAGS="$CFLAGS $NETCDF_CFLAGS" cat > conftest.$ac_ext < int main() { nc_create("foo", NC_CLOBBER, NULL); ; return 0; } EOF -if { (eval echo configure:7296: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7330: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then : else echo "configure: failed program was:" >&5 @@ -7300,14 +7334,14 @@ else rm -rf conftest* cat > conftest.$ac_ext < int main() { nc_create("foo", NC_CLOBBER, NULL); ; return 0; } EOF -if { (eval echo configure:7311: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7345: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* NETCDF_LIBS="$NETCDF_LIBS" else @@ -7338,7 +7372,7 @@ fi # GEOS option echo $ac_n "checking whether to use GEOS""... $ac_c" 1>&6 -echo "configure:7342: checking whether to use GEOS" >&5 +echo "configure:7376: checking whether to use GEOS" >&5 GEOS_LIBS= GEOS_CFLAGS= @@ -7356,7 +7390,7 @@ else # Extract the first word of "geos-config", so it can be a program name with args. set dummy geos-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7360: checking for $ac_word" >&5 +echo "configure:7394: checking for $ac_word" >&5 case "$GEOS_CONFIG" in /*) @@ -7404,15 +7438,15 @@ for ac_hdr in geos_c.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7408: checking for $ac_hdr" >&5 +echo "configure:7442: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7416: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7450: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7451,13 +7485,13 @@ LDFLAGS="$GEOS_LIBS $LDFLAGS" echo $ac_n "checking for initGEOS in -lgeos_c""... $ac_c" 1>&6 -echo "configure:7455: checking for initGEOS in -lgeos_c" >&5 +echo "configure:7489: checking for initGEOS in -lgeos_c" >&5 ac_lib_var=`echo geos_c'_'initGEOS | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lgeos_c $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7506: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7512,7 +7546,7 @@ fi echo $ac_n "checking whether to use TIFF""... $ac_c" 1>&6 -echo "configure:7516: checking whether to use TIFF" >&5 +echo "configure:7550: checking whether to use TIFF" >&5 echo "$ac_t"""$with_tiff"" 1>&6 case "$with_tiff" in "no") USE_TIFF= ;; @@ -7532,7 +7566,7 @@ if test -n "$USE_TIFF"; then echo $ac_n "checking for location of TIFF includes""... $ac_c" 1>&6 -echo "configure:7536: checking for location of TIFF includes" >&5 +echo "configure:7570: checking for location of TIFF includes" >&5 case "$with_tiff_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-tiff-includes." 1>&2; exit 1; } @@ -7558,15 +7592,15 @@ for ac_hdr in tiffio.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7562: checking for $ac_hdr" >&5 +echo "configure:7596: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7570: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7604: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7600,7 +7634,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of TIFF library""... $ac_c" 1>&6 -echo "configure:7604: checking for location of TIFF library" >&5 +echo "configure:7638: checking for location of TIFF library" >&5 case "$with_tiff_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-tiff-libs." 1>&2; exit 1; } @@ -7631,13 +7665,13 @@ LDFLAGS="$TIFF_LIBRARY_DIRS $LDFLAGS" echo $ac_n "checking for TIFFOpen in -ltiff""... $ac_c" 1>&6 -echo "configure:7635: checking for TIFFOpen in -ltiff" >&5 +echo "configure:7669: checking for TIFFOpen in -ltiff" >&5 ac_lib_var=`echo tiff'_'TIFFOpen | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ltiff $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7686: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7667,13 +7701,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for TIFFOpen in -ltiff""... $ac_c" 1>&6 -echo "configure:7671: checking for TIFFOpen in -ltiff" >&5 +echo "configure:7705: checking for TIFFOpen in -ltiff" >&5 ac_lib_var=`echo tiff'_'TIFFOpen | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ltiff $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7722: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7703,13 +7737,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for TIFFOpen in -ltiff""... $ac_c" 1>&6 -echo "configure:7707: checking for TIFFOpen in -ltiff" >&5 +echo "configure:7741: checking for TIFFOpen in -ltiff" >&5 ac_lib_var=`echo tiff'_'TIFFOpen | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ltiff $ZLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7758: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7739,13 +7773,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for TIFFOpen in -ltiff""... $ac_c" 1>&6 -echo "configure:7743: checking for TIFFOpen in -ltiff" >&5 +echo "configure:7777: checking for TIFFOpen in -ltiff" >&5 ac_lib_var=`echo tiff'_'TIFFOpen | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ltiff $ZLIB $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7794: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7775,13 +7809,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for TIFFOpen in -ltiff""... $ac_c" 1>&6 -echo "configure:7779: checking for TIFFOpen in -ltiff" >&5 +echo "configure:7813: checking for TIFFOpen in -ltiff" >&5 ac_lib_var=`echo tiff'_'TIFFOpen | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ltiff -ljpeg $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7830: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7811,13 +7845,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for TIFFOpen in -ltiff""... $ac_c" 1>&6 -echo "configure:7815: checking for TIFFOpen in -ltiff" >&5 +echo "configure:7849: checking for TIFFOpen in -ltiff" >&5 ac_lib_var=`echo tiff'_'TIFFOpen | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ltiff -ljpeg $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7866: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7847,13 +7881,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for TIFFOpen in -ltiff""... $ac_c" 1>&6 -echo "configure:7851: checking for TIFFOpen in -ltiff" >&5 +echo "configure:7885: checking for TIFFOpen in -ltiff" >&5 ac_lib_var=`echo tiff'_'TIFFOpen | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ltiff -ljpeg $ZLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7902: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7883,13 +7917,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for TIFFOpen in -ltiff""... $ac_c" 1>&6 -echo "configure:7887: checking for TIFFOpen in -ltiff" >&5 +echo "configure:7921: checking for TIFFOpen in -ltiff" >&5 ac_lib_var=`echo tiff'_'TIFFOpen | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ltiff -ljpeg $ZLIB $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7938: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7998,7 +8032,7 @@ fi # $USE_TIFF echo $ac_n "checking whether to use PNG""... $ac_c" 1>&6 -echo "configure:8002: checking whether to use PNG" >&5 +echo "configure:8036: checking whether to use PNG" >&5 echo "$ac_t"""$with_png"" 1>&6 case "$with_png" in "no") USE_PNG= ;; @@ -8017,7 +8051,7 @@ if test -n "$USE_PNG"; then echo $ac_n "checking for location of PNG includes""... $ac_c" 1>&6 -echo "configure:8021: checking for location of PNG includes" >&5 +echo "configure:8055: checking for location of PNG includes" >&5 case "$with_png_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-png-includes." 1>&2; exit 1; } @@ -8043,15 +8077,15 @@ for ac_hdr in png.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:8047: checking for $ac_hdr" >&5 +echo "configure:8081: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8055: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8089: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8085,7 +8119,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of PNG library""... $ac_c" 1>&6 -echo "configure:8089: checking for location of PNG library" >&5 +echo "configure:8123: checking for location of PNG library" >&5 case "$with_png_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-png-libs." 1>&2; exit 1; } @@ -8110,13 +8144,13 @@ LDFLAGS="$PNGLIB $LDFLAGS" echo $ac_n "checking for png_read_image in -lpng""... $ac_c" 1>&6 -echo "configure:8114: checking for png_read_image in -lpng" >&5 +echo "configure:8148: checking for png_read_image in -lpng" >&5 ac_lib_var=`echo png'_'png_read_image | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lpng $ZLIB $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8165: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8169,7 +8203,7 @@ fi # $USE_PNG echo $ac_n "checking whether to use PostgreSQL""... $ac_c" 1>&6 -echo "configure:8173: checking whether to use PostgreSQL" >&5 +echo "configure:8207: checking whether to use PostgreSQL" >&5 echo "$ac_t"""$with_postgres"" 1>&6 case "$with_postgres" in "no") USE_POSTGRES= ;; @@ -8196,7 +8230,7 @@ if test -n "$USE_POSTGRES"; then echo $ac_n "checking for location of PostgreSQL includes""... $ac_c" 1>&6 -echo "configure:8200: checking for location of PostgreSQL includes" >&5 +echo "configure:8234: checking for location of PostgreSQL includes" >&5 case "$with_postgres_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-postgres-includes." 1>&2; exit 1; } @@ -8222,15 +8256,15 @@ for ac_hdr in libpq-fe.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:8226: checking for $ac_hdr" >&5 +echo "configure:8260: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8234: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8268: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8268,7 +8302,7 @@ if test -n "$USE_POSTGRES"; then echo $ac_n "checking for location of PostgreSQL library""... $ac_c" 1>&6 -echo "configure:8272: checking for location of PostgreSQL library" >&5 +echo "configure:8306: checking for location of PostgreSQL library" >&5 case "$with_postgres_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-postgres-libs." 1>&2; exit 1; } @@ -8297,13 +8331,13 @@ LDFLAGS="$PQLIBPATH $LDFLAGS" echo $ac_n "checking for PQsetdbLogin in -lpq""... $ac_c" 1>&6 -echo "configure:8301: checking for PQsetdbLogin in -lpq" >&5 +echo "configure:8335: checking for PQsetdbLogin in -lpq" >&5 ac_lib_var=`echo pq'_'PQsetdbLogin | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lpq $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8352: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8333,13 +8367,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for PQsetdbLogin in -lpq""... $ac_c" 1>&6 -echo "configure:8337: checking for PQsetdbLogin in -lpq" >&5 +echo "configure:8371: checking for PQsetdbLogin in -lpq" >&5 ac_lib_var=`echo pq'_'PQsetdbLogin | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lpq -lssl -lcrypto $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8388: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8369,13 +8403,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for PQsetdbLogin in -lpq""... $ac_c" 1>&6 -echo "configure:8373: checking for PQsetdbLogin in -lpq" >&5 +echo "configure:8407: checking for PQsetdbLogin in -lpq" >&5 ac_lib_var=`echo pq'_'PQsetdbLogin | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lpq -lcrypt $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8424: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8405,13 +8439,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for PQsetdbLogin in -lpq""... $ac_c" 1>&6 -echo "configure:8409: checking for PQsetdbLogin in -lpq" >&5 +echo "configure:8443: checking for PQsetdbLogin in -lpq" >&5 ac_lib_var=`echo pq'_'PQsetdbLogin | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lpq -lcrypt -lssl -lcrypto $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8460: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8479,13 +8513,13 @@ LDFLAGS=${ac_save_ldflags} ac_save_ldflags="$LDFLAGS" LDFLAGS="$LDFLAGS $PQLIBPATH" echo $ac_n "checking for PQcmdTuples in -lpq""... $ac_c" 1>&6 -echo "configure:8483: checking for PQcmdTuples in -lpq" >&5 +echo "configure:8517: checking for PQcmdTuples in -lpq" >&5 ac_lib_var=`echo pq'_'PQcmdTuples | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lpq $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8534: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8518,13 +8552,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for PQcmdTuples in -lpq""... $ac_c" 1>&6 -echo "configure:8522: checking for PQcmdTuples in -lpq" >&5 +echo "configure:8556: checking for PQcmdTuples in -lpq" >&5 ac_lib_var=`echo pq'_'PQcmdTuples | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lpq -lcrypt $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8573: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8578,7 +8612,7 @@ fi # $USE_POSTGRES echo $ac_n "checking whether to use MySQL""... $ac_c" 1>&6 -echo "configure:8582: checking whether to use MySQL" >&5 +echo "configure:8616: checking whether to use MySQL" >&5 echo "$ac_t"""$with_mysql"" 1>&6 case "$with_mysql" in "no") USE_MYSQL= ;; @@ -8598,7 +8632,7 @@ if test -n "$USE_MYSQL"; then echo $ac_n "checking for location of MySQL includes""... $ac_c" 1>&6 -echo "configure:8602: checking for location of MySQL includes" >&5 +echo "configure:8636: checking for location of MySQL includes" >&5 case "$with_mysql_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-mysql-includes." 1>&2; exit 1; } @@ -8624,15 +8658,15 @@ for ac_hdr in mysql.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:8628: checking for $ac_hdr" >&5 +echo "configure:8662: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8636: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8670: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8669,7 +8703,7 @@ if test -n "$USE_MYSQL"; then echo $ac_n "checking for location of MySQL library""... $ac_c" 1>&6 -echo "configure:8673: checking for location of MySQL library" >&5 +echo "configure:8707: checking for location of MySQL library" >&5 case "$with_mysql_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-mysql-libs." 1>&2; exit 1; } @@ -8700,13 +8734,13 @@ LDFLAGS="$MYSQLLIBPATH $LDFLAGS" echo $ac_n "checking for mysql_query in -lmysqlclient""... $ac_c" 1>&6 -echo "configure:8704: checking for mysql_query in -lmysqlclient" >&5 +echo "configure:8738: checking for mysql_query in -lmysqlclient" >&5 ac_lib_var=`echo mysqlclient'_'mysql_query | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lmysqlclient $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8755: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8736,13 +8770,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for mysql_query in -lmysqlclient""... $ac_c" 1>&6 -echo "configure:8740: checking for mysql_query in -lmysqlclient" >&5 +echo "configure:8774: checking for mysql_query in -lmysqlclient" >&5 ac_lib_var=`echo mysqlclient'_'mysql_query | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lmysqlclient $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8791: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8772,13 +8806,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for mysql_query in -lmysqlclient""... $ac_c" 1>&6 -echo "configure:8776: checking for mysql_query in -lmysqlclient" >&5 +echo "configure:8810: checking for mysql_query in -lmysqlclient" >&5 ac_lib_var=`echo mysqlclient'_'mysql_query | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lmysqlclient $SOCKLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8827: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8808,13 +8842,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for mysql_query in -lmysqlclient""... $ac_c" 1>&6 -echo "configure:8812: checking for mysql_query in -lmysqlclient" >&5 +echo "configure:8846: checking for mysql_query in -lmysqlclient" >&5 ac_lib_var=`echo mysqlclient'_'mysql_query | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lmysqlclient $SOCKLIB $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8863: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8844,13 +8878,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for mysql_query in -lmysqlclient""... $ac_c" 1>&6 -echo "configure:8848: checking for mysql_query in -lmysqlclient" >&5 +echo "configure:8882: checking for mysql_query in -lmysqlclient" >&5 ac_lib_var=`echo mysqlclient'_'mysql_query | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lmysqlclient $ZLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8899: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8880,13 +8914,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for mysql_query in -lmysqlclient""... $ac_c" 1>&6 -echo "configure:8884: checking for mysql_query in -lmysqlclient" >&5 +echo "configure:8918: checking for mysql_query in -lmysqlclient" >&5 ac_lib_var=`echo mysqlclient'_'mysql_query | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lmysqlclient $ZLIB $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8916,13 +8950,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for mysql_query in -lmysqlclient""... $ac_c" 1>&6 -echo "configure:8920: checking for mysql_query in -lmysqlclient" >&5 +echo "configure:8954: checking for mysql_query in -lmysqlclient" >&5 ac_lib_var=`echo mysqlclient'_'mysql_query | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lmysqlclient $ZLIB $SOCKLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8971: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8952,13 +8986,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for mysql_query in -lmysqlclient""... $ac_c" 1>&6 -echo "configure:8956: checking for mysql_query in -lmysqlclient" >&5 +echo "configure:8990: checking for mysql_query in -lmysqlclient" >&5 ac_lib_var=`echo mysqlclient'_'mysql_query | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lmysqlclient $ZLIB $SOCKLIB $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9007: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9059,7 +9093,7 @@ LDFLAGS=${ac_save_ldflags} # Extract the first word of "mysql_config", so it can be a program name with args. set dummy mysql_config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:9063: checking for $ac_word" >&5 +echo "configure:9097: checking for $ac_word" >&5 case "$MYSQLD_CONFIG" in /*) @@ -9108,10 +9142,10 @@ cross_compiling=$ac_cv_prog_cxx_cross LIBS="$MYSQLDLIB $LIBS" echo $ac_n "checking for mysql_server_init""... $ac_c" 1>&6 -echo "configure:9112: checking for mysql_server_init" >&5 +echo "configure:9146: checking for mysql_server_init" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9175: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_mysql_server_init=yes" else @@ -9189,7 +9223,7 @@ fi # $USE_MYSQL echo $ac_n "checking whether to use SQLite""... $ac_c" 1>&6 -echo "configure:9193: checking whether to use SQLite" >&5 +echo "configure:9227: checking whether to use SQLite" >&5 echo "$ac_t"""$with_sqlite"" 1>&6 case "$with_sqlite" in "no") USE_SQLITE= ;; @@ -9209,7 +9243,7 @@ if test -n "$USE_SQLITE"; then echo $ac_n "checking for location of SQLite includes""... $ac_c" 1>&6 -echo "configure:9213: checking for location of SQLite includes" >&5 +echo "configure:9247: checking for location of SQLite includes" >&5 case "$with_sqlite_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-sqlite-includes." 1>&2; exit 1; } @@ -9235,15 +9269,15 @@ for ac_hdr in sqlite3.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:9239: checking for $ac_hdr" >&5 +echo "configure:9273: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:9247: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:9281: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -9286,7 +9320,7 @@ if test -n "$USE_SQLITE"; then echo $ac_n "checking for location of SQLite library""... $ac_c" 1>&6 -echo "configure:9290: checking for location of SQLite library" >&5 +echo "configure:9324: checking for location of SQLite library" >&5 case "$with_sqlite_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-sqlite-libs." 1>&2; exit 1; } @@ -9315,13 +9349,13 @@ LDFLAGS="$SQLITELIBPATH $LDFLAGS" echo $ac_n "checking for sqlite3_open in -lsqlite3""... $ac_c" 1>&6 -echo "configure:9319: checking for sqlite3_open in -lsqlite3" >&5 +echo "configure:9353: checking for sqlite3_open in -lsqlite3" >&5 ac_lib_var=`echo sqlite3'_'sqlite3_open | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lsqlite3 $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9370: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9351,13 +9385,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for sqlite3_open in -lsqlite3""... $ac_c" 1>&6 -echo "configure:9355: checking for sqlite3_open in -lsqlite3" >&5 +echo "configure:9389: checking for sqlite3_open in -lsqlite3" >&5 ac_lib_var=`echo sqlite3'_'sqlite3_open | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lsqlite3 $DLLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9406: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9387,13 +9421,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for sqlite3_open in -lsqlite3""... $ac_c" 1>&6 -echo "configure:9391: checking for sqlite3_open in -lsqlite3" >&5 +echo "configure:9425: checking for sqlite3_open in -lsqlite3" >&5 ac_lib_var=`echo sqlite3'_'sqlite3_open | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lsqlite3 $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9442: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9423,13 +9457,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for sqlite3_open in -lsqlite3""... $ac_c" 1>&6 -echo "configure:9427: checking for sqlite3_open in -lsqlite3" >&5 +echo "configure:9461: checking for sqlite3_open in -lsqlite3" >&5 ac_lib_var=`echo sqlite3'_'sqlite3_open | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lsqlite3 $MATHLIB $DLLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9478: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9515,7 +9549,7 @@ OPENGL_AQUA= OPENGL_WINDOWS= echo $ac_n "checking whether to use OpenGL""... $ac_c" 1>&6 -echo "configure:9519: checking whether to use OpenGL" >&5 +echo "configure:9553: checking whether to use OpenGL" >&5 echo "$ac_t"""$with_opengl"" 1>&6 case "$with_opengl" in n|no) @@ -9549,7 +9583,7 @@ if test "$OPENGL_X11" = 1 ; then echo $ac_n "checking for location of OpenGL includes""... $ac_c" 1>&6 -echo "configure:9553: checking for location of OpenGL includes" >&5 +echo "configure:9587: checking for location of OpenGL includes" >&5 case "$with_opengl_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-opengl-includes." 1>&2; exit 1; } @@ -9575,15 +9609,15 @@ for ac_hdr in GL/gl.h GL/glu.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:9579: checking for $ac_hdr" >&5 +echo "configure:9613: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:9587: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:9621: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -9617,7 +9651,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of OpenGL library""... $ac_c" 1>&6 -echo "configure:9621: checking for location of OpenGL library" >&5 +echo "configure:9655: checking for location of OpenGL library" >&5 case "$with_opengl_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-opengl-libs." 1>&2; exit 1; } @@ -9646,13 +9680,13 @@ LDFLAGS="$OPENGL_LIB_PATH $LDFLAGS" echo $ac_n "checking for glBegin in -lGL""... $ac_c" 1>&6 -echo "configure:9650: checking for glBegin in -lGL" >&5 +echo "configure:9684: checking for glBegin in -lGL" >&5 ac_lib_var=`echo GL'_'glBegin | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lGL $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9701: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9682,13 +9716,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for glBegin in -lGL""... $ac_c" 1>&6 -echo "configure:9686: checking for glBegin in -lGL" >&5 +echo "configure:9720: checking for glBegin in -lGL" >&5 ac_lib_var=`echo GL'_'glBegin | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lGL $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $MATHLIB -lXext $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9737: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9718,13 +9752,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for glBegin in -lGL""... $ac_c" 1>&6 -echo "configure:9722: checking for glBegin in -lGL" >&5 +echo "configure:9756: checking for glBegin in -lGL" >&5 ac_lib_var=`echo GL'_'glBegin | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lGL $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $MATHLIB -lpthread $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9773: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9754,13 +9788,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for glBegin in -lGL""... $ac_c" 1>&6 -echo "configure:9758: checking for glBegin in -lGL" >&5 +echo "configure:9792: checking for glBegin in -lGL" >&5 ac_lib_var=`echo GL'_'glBegin | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lGL $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $MATHLIB -lpthread -lXext $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9809: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9833,13 +9867,13 @@ LDFLAGS="$OPENGL_LIB_PATH $LDFLAGS" echo $ac_n "checking for gluBeginCurve in -lGLU""... $ac_c" 1>&6 -echo "configure:9837: checking for gluBeginCurve in -lGLU" >&5 +echo "configure:9871: checking for gluBeginCurve in -lGLU" >&5 ac_lib_var=`echo GLU'_'gluBeginCurve | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lGLU $OPENGLLIB $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9888: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9869,13 +9903,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for gluBeginCurve in -lGLU""... $ac_c" 1>&6 -echo "configure:9873: checking for gluBeginCurve in -lGLU" >&5 +echo "configure:9907: checking for gluBeginCurve in -lGLU" >&5 ac_lib_var=`echo GLU'_'gluBeginCurve | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lGLU $OPENGLLIB $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $MATHLIB -lstdc++ $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9924: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9933,10 +9967,10 @@ ac_save_ldflags="$LDFLAGS" LIBS=" $OPENGLLIB $LIBS" LDFLAGS=" $LDFLAGS" echo $ac_n "checking for glXCreatePbuffer""... $ac_c" 1>&6 -echo "configure:9937: checking for glXCreatePbuffer" >&5 +echo "configure:9971: checking for glXCreatePbuffer" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9997: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_glXCreatePbuffer=yes" else @@ -9996,10 +10030,10 @@ ac_save_ldflags="$LDFLAGS" LIBS=" $OPENGLLIB $LIBS" LDFLAGS=" $LDFLAGS" echo $ac_n "checking for glXCreateGLXPixmap""... $ac_c" 1>&6 -echo "configure:10000: checking for glXCreateGLXPixmap" >&5 +echo "configure:10034: checking for glXCreateGLXPixmap" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_glXCreateGLXPixmap=yes" else @@ -10065,7 +10099,7 @@ if test "$OPENGL_AQUA" = 1 ; then echo $ac_n "checking for location of OpenGL framework""... $ac_c" 1>&6 -echo "configure:10069: checking for location of OpenGL framework" >&5 +echo "configure:10103: checking for location of OpenGL framework" >&5 case "$with_opengl_framework" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-opengl-framework." 1>&2; exit 1; } @@ -10089,15 +10123,15 @@ for ac_hdr in OpenGL/gl.h OpenGL/glu.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10093: checking for $ac_hdr" >&5 +echo "configure:10127: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10101: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10135: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10133,10 +10167,10 @@ ac_save_ldflags="$LDFLAGS" LIBS="-framework OpenGL -framework AGL -framework ApplicationServices $LIBS" LDFLAGS="$OPENGLPATH $LDFLAGS" echo $ac_n "checking for glBegin""... $ac_c" 1>&6 -echo "configure:10137: checking for glBegin" >&5 +echo "configure:10171: checking for glBegin" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10197: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_glBegin=yes" else @@ -10196,10 +10230,10 @@ ac_save_ldflags="$LDFLAGS" LIBS=" $OPENGLLIB $LIBS" LDFLAGS="$OPENGLPATH $LDFLAGS" echo $ac_n "checking for gluBeginCurve""... $ac_c" 1>&6 -echo "configure:10200: checking for gluBeginCurve" >&5 +echo "configure:10234: checking for gluBeginCurve" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10260: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gluBeginCurve=yes" else @@ -10270,7 +10304,7 @@ if test "$OPENGL_WINDOWS" = 1 ; then echo $ac_n "checking for location of OpenGL includes""... $ac_c" 1>&6 -echo "configure:10274: checking for location of OpenGL includes" >&5 +echo "configure:10308: checking for location of OpenGL includes" >&5 case "$with_opengl_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-opengl-includes." 1>&2; exit 1; } @@ -10296,15 +10330,15 @@ for ac_hdr in GL/gl.h GL/glu.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10300: checking for $ac_hdr" >&5 +echo "configure:10334: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10308: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10342: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10338,7 +10372,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of OpenGL library""... $ac_c" 1>&6 -echo "configure:10342: checking for location of OpenGL library" >&5 +echo "configure:10376: checking for location of OpenGL library" >&5 case "$with_opengl_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-opengl-libs." 1>&2; exit 1; } @@ -10363,18 +10397,18 @@ CFLAGS="$CFLAGS $OPENGLINC" ac_save_ldflags="$LDFLAGS" ac_save_libs="$LIBS" echo $ac_n "checking for OpenGL library""... $ac_c" 1>&6 -echo "configure:10367: checking for OpenGL library" >&5 +echo "configure:10401: checking for OpenGL library" >&5 LDFLAGS="$OPENGL_LIB_PATH $LDFLAGS" LIBS="-lopengl32 " cat > conftest.$ac_ext < int main() { glEnd(); ; return 0; } EOF -if { (eval echo configure:10378: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10412: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* echo "$ac_t""found" 1>&6 @@ -10398,18 +10432,18 @@ LDFLAGS=${ac_save_ldflags} ac_save_ldflags="$LDFLAGS" ac_save_libs="$LIBS" echo $ac_n "checking for GLU library""... $ac_c" 1>&6 -echo "configure:10402: checking for GLU library" >&5 +echo "configure:10436: checking for GLU library" >&5 LDFLAGS="$OPENGL_LIB_PATH $LDFLAGS" LIBS="-lglu32 $OPENGLLIB " cat > conftest.$ac_ext < int main() { gluNewQuadric(); ; return 0; } EOF -if { (eval echo configure:10413: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10447: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* echo "$ac_t""found" 1>&6 @@ -10458,7 +10492,7 @@ fi # $USE_OPENGL echo $ac_n "checking whether to use ODBC""... $ac_c" 1>&6 -echo "configure:10462: checking whether to use ODBC" >&5 +echo "configure:10496: checking whether to use ODBC" >&5 echo "$ac_t"""$with_odbc"" 1>&6 case "$with_odbc" in "no") USE_ODBC= ;; @@ -10477,7 +10511,7 @@ if test -n "$USE_ODBC"; then echo $ac_n "checking for location of ODBC includes""... $ac_c" 1>&6 -echo "configure:10481: checking for location of ODBC includes" >&5 +echo "configure:10515: checking for location of ODBC includes" >&5 case "$with_odbc_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-odbc-includes." 1>&2; exit 1; } @@ -10503,15 +10537,15 @@ for ac_hdr in sql.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10507: checking for $ac_hdr" >&5 +echo "configure:10541: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10515: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10549: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10545,7 +10579,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of ODBC library""... $ac_c" 1>&6 -echo "configure:10549: checking for location of ODBC library" >&5 +echo "configure:10583: checking for location of ODBC library" >&5 case "$with_odbc_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-odbc-libs." 1>&2; exit 1; } @@ -10570,13 +10604,13 @@ LDFLAGS="$ODBCLIB $LDFLAGS" echo $ac_n "checking for SQLConnect in -lodbc""... $ac_c" 1>&6 -echo "configure:10574: checking for SQLConnect in -lodbc" >&5 +echo "configure:10608: checking for SQLConnect in -lodbc" >&5 ac_lib_var=`echo odbc'_'SQLConnect | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lodbc $ICONVLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10625: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10612,13 +10646,13 @@ LDFLAGS="$ODBCLIB $LDFLAGS" echo $ac_n "checking for SQLConnect in -liodbc""... $ac_c" 1>&6 -echo "configure:10616: checking for SQLConnect in -liodbc" >&5 +echo "configure:10650: checking for SQLConnect in -liodbc" >&5 ac_lib_var=`echo iodbc'_'SQLConnect | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-liodbc $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10667: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10654,11 +10688,11 @@ CFLAGS="$CFLAGS $ODBCINC" ac_save_ldflags="$LDFLAGS" ac_save_libs="$LIBS" echo $ac_n "checking for ODBC library""... $ac_c" 1>&6 -echo "configure:10658: checking for ODBC library" >&5 +echo "configure:10692: checking for ODBC library" >&5 LDFLAGS="$ODBCLIB $LDFLAGS" LIBS="-lodbc32 " cat > conftest.$ac_ext < #include @@ -10666,7 +10700,7 @@ int main() { SQLAllocEnv((SQLHENV *)0); ; return 0; } EOF -if { (eval echo configure:10670: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10704: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* echo "$ac_t""found" 1>&6 @@ -10715,7 +10749,7 @@ fi # $USE_ODBC echo $ac_n "checking whether to use FFTW""... $ac_c" 1>&6 -echo "configure:10719: checking whether to use FFTW" >&5 +echo "configure:10753: checking whether to use FFTW" >&5 echo "$ac_t"""$with_fftw"" 1>&6 case "$with_fftw" in "no") USE_FFTW= ;; @@ -10734,7 +10768,7 @@ if test -n "$USE_FFTW"; then echo $ac_n "checking for location of FFTW includes""... $ac_c" 1>&6 -echo "configure:10738: checking for location of FFTW includes" >&5 +echo "configure:10772: checking for location of FFTW includes" >&5 case "$with_fftw_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-fftw-includes." 1>&2; exit 1; } @@ -10760,15 +10794,15 @@ for ac_hdr in fftw3.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10764: checking for $ac_hdr" >&5 +echo "configure:10798: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10772: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10806: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10796,15 +10830,15 @@ for ac_hdr in fftw.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10800: checking for $ac_hdr" >&5 +echo "configure:10834: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10808: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10842: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10832,15 +10866,15 @@ for ac_hdr in dfftw.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:10836: checking for $ac_hdr" >&5 +echo "configure:10870: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:10844: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:10878: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -10886,7 +10920,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of FFTW library""... $ac_c" 1>&6 -echo "configure:10890: checking for location of FFTW library" >&5 +echo "configure:10924: checking for location of FFTW library" >&5 case "$with_fftw_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-fftw-libs." 1>&2; exit 1; } @@ -10911,13 +10945,13 @@ LDFLAGS="$FFTWLIB $LDFLAGS" echo $ac_n "checking for fftw_execute in -lfftw3""... $ac_c" 1>&6 -echo "configure:10915: checking for fftw_execute in -lfftw3" >&5 +echo "configure:10949: checking for fftw_execute in -lfftw3" >&5 ac_lib_var=`echo fftw3'_'fftw_execute | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lfftw3 $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:10966: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10953,13 +10987,13 @@ LDFLAGS="$FFTWLIB $LDFLAGS" echo $ac_n "checking for fftwnd_one in -lfftw""... $ac_c" 1>&6 -echo "configure:10957: checking for fftwnd_one in -lfftw" >&5 +echo "configure:10991: checking for fftwnd_one in -lfftw" >&5 ac_lib_var=`echo fftw'_'fftwnd_one | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lfftw $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11008: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -10995,13 +11029,13 @@ LDFLAGS="$FFTWLIB $LDFLAGS" echo $ac_n "checking for fftwnd_one in -ldfftw""... $ac_c" 1>&6 -echo "configure:10999: checking for fftwnd_one in -ldfftw" >&5 +echo "configure:11033: checking for fftwnd_one in -ldfftw" >&5 ac_lib_var=`echo dfftw'_'fftwnd_one | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ldfftw $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11050: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11069,7 +11103,7 @@ fi # $USE_FFTW echo $ac_n "checking whether to use BLAS""... $ac_c" 1>&6 -echo "configure:11073: checking whether to use BLAS" >&5 +echo "configure:11107: checking whether to use BLAS" >&5 echo "$ac_t"""$with_blas"" 1>&6 case "$with_blas" in "no") USE_BLAS= ;; @@ -11090,7 +11124,7 @@ if test -n "$USE_BLAS"; then echo $ac_n "checking for location of BLAS includes""... $ac_c" 1>&6 -echo "configure:11094: checking for location of BLAS includes" >&5 +echo "configure:11128: checking for location of BLAS includes" >&5 case "$with_blas_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-blas-includes." 1>&2; exit 1; } @@ -11110,7 +11144,7 @@ fi echo $ac_n "checking for location of BLAS library""... $ac_c" 1>&6 -echo "configure:11114: checking for location of BLAS library" >&5 +echo "configure:11148: checking for location of BLAS library" >&5 case "$with_blas_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-blas-libs." 1>&2; exit 1; } @@ -11136,15 +11170,15 @@ for ac_hdr in cblas.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:11140: checking for $ac_hdr" >&5 +echo "configure:11174: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:11148: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:11182: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -11179,13 +11213,13 @@ LDFLAGS="$BLASLIB $LDFLAGS" echo $ac_n "checking for dnrm2_ in -lblas""... $ac_c" 1>&6 -echo "configure:11183: checking for dnrm2_ in -lblas" >&5 +echo "configure:11217: checking for dnrm2_ in -lblas" >&5 ac_lib_var=`echo blas'_'dnrm2_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lblas $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11215,13 +11249,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dnrm2_ in -lblas""... $ac_c" 1>&6 -echo "configure:11219: checking for dnrm2_ in -lblas" >&5 +echo "configure:11253: checking for dnrm2_ in -lblas" >&5 ac_lib_var=`echo blas'_'dnrm2_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lblas $MATHLIB -lg2c $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11270: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11276,13 +11310,13 @@ blas_ok=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$BLASLIB $LDFLAGS" echo $ac_n "checking for ATL_xerbla in -latlas""... $ac_c" 1>&6 -echo "configure:11280: checking for ATL_xerbla in -latlas" >&5 +echo "configure:11314: checking for ATL_xerbla in -latlas" >&5 ac_lib_var=`echo atlas'_'ATL_xerbla | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-latlas $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11331: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11308,13 +11342,13 @@ LIBS="$ac_save_LIBS" if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for sgemm_ in -lf77blas""... $ac_c" 1>&6 -echo "configure:11312: checking for sgemm_ in -lf77blas" >&5 +echo "configure:11346: checking for sgemm_ in -lf77blas" >&5 ac_lib_var=`echo f77blas'_'sgemm_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lf77blas -latlas $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11363: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11340,13 +11374,13 @@ LIBS="$ac_save_LIBS" if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for cblas_dgemm in -lcblas""... $ac_c" 1>&6 -echo "configure:11344: checking for cblas_dgemm in -lcblas" >&5 +echo "configure:11378: checking for cblas_dgemm in -lcblas" >&5 ac_lib_var=`echo cblas'_'cblas_dgemm | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lcblas -lf77blas -latlas $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11395: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11403,16 +11437,16 @@ if test $blas_ok = no; then save_LIBS="$LIBS" LIBS="$vlib_flags $LIBS" echo $ac_n "checking for sgemm in $vlib_flags""... $ac_c" 1>&6 -echo "configure:11407: checking for sgemm in $vlib_flags" >&5 +echo "configure:11441: checking for sgemm in $vlib_flags" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11450: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* blas_ok=yes; BLASLIB="$vlib_flags" else @@ -11430,13 +11464,13 @@ fi # BLAS in PhiPACK libraries? (requires generic BLAS, too) if test $blas_ok = no; then echo $ac_n "checking for sgemm_ in -lblas""... $ac_c" 1>&6 -echo "configure:11434: checking for sgemm_ in -lblas" >&5 +echo "configure:11468: checking for sgemm_ in -lblas" >&5 ac_lib_var=`echo blas'_'sgemm_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lblas $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11485: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11462,13 +11496,13 @@ LIBS="$ac_save_LIBS" if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for dgemm_ in -ldgemm""... $ac_c" 1>&6 -echo "configure:11466: checking for dgemm_ in -ldgemm" >&5 +echo "configure:11500: checking for dgemm_ in -ldgemm" >&5 ac_lib_var=`echo dgemm'_'dgemm_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-ldgemm -lblas $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11517: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11494,13 +11528,13 @@ LIBS="$ac_save_LIBS" if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for sgemm_ in -lsgemm""... $ac_c" 1>&6 -echo "configure:11498: checking for sgemm_ in -lsgemm" >&5 +echo "configure:11532: checking for sgemm_ in -lsgemm" >&5 ac_lib_var=`echo sgemm'_'sgemm_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lsgemm -lblas $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11549: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11545,13 +11579,13 @@ fi if test $blas_ok = no; then if test "x$GCC" != xyes; then # only works with Sun CC echo $ac_n "checking for acosp in -lsunmath""... $ac_c" 1>&6 -echo "configure:11549: checking for acosp in -lsunmath" >&5 +echo "configure:11583: checking for acosp in -lsunmath" >&5 ac_lib_var=`echo sunmath'_'acosp | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lsunmath $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11600: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11577,13 +11611,13 @@ LIBS="$ac_save_LIBS" if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for sgemm_ in -lsunperf""... $ac_c" 1>&6 -echo "configure:11581: checking for sgemm_ in -lsunperf" >&5 +echo "configure:11615: checking for sgemm_ in -lsunperf" >&5 ac_lib_var=`echo sunperf'_'sgemm_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lsunperf -lsunmath $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11632: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11624,13 +11658,13 @@ fi # Generic BLAS library if test $blas_ok = no; then echo $ac_n "checking for sgemm_ in -lblas""... $ac_c" 1>&6 -echo "configure:11628: checking for sgemm_ in -lblas" >&5 +echo "configure:11662: checking for sgemm_ in -lblas" >&5 ac_lib_var=`echo blas'_'sgemm_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lblas $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11679: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11680,7 +11714,7 @@ fi # $USE_BLAS echo $ac_n "checking whether to use LAPACK""... $ac_c" 1>&6 -echo "configure:11684: checking whether to use LAPACK" >&5 +echo "configure:11718: checking whether to use LAPACK" >&5 echo "$ac_t"""$with_lapack"" 1>&6 case "$with_lapack" in "no") USE_LAPACK= ;; @@ -11705,7 +11739,7 @@ lapack_ok=no echo $ac_n "checking for location of LAPACK includes""... $ac_c" 1>&6 -echo "configure:11709: checking for location of LAPACK includes" >&5 +echo "configure:11743: checking for location of LAPACK includes" >&5 case "$with_lapack_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-lapack-includes." 1>&2; exit 1; } @@ -11725,7 +11759,7 @@ fi echo $ac_n "checking for location of LAPACK library""... $ac_c" 1>&6 -echo "configure:11729: checking for location of LAPACK library" >&5 +echo "configure:11763: checking for location of LAPACK library" >&5 case "$with_lapack_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-lapack-libs." 1>&2; exit 1; } @@ -11751,15 +11785,15 @@ for ac_hdr in clapack.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:11755: checking for $ac_hdr" >&5 +echo "configure:11789: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:11763: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:11797: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -11791,10 +11825,10 @@ if test lapack_ok=no; then save_LIBS="$LIBS"; LIBS="$LIBS $BLASLIB $MATHLIB $FLIBS" save_LDFLAGS="$LDFLAGS"; LDFLAGS="$LAPACKLIB $LDFLAGS" echo $ac_n "checking for dsegv_""... $ac_c" 1>&6 -echo "configure:11795: checking for dsegv_" >&5 +echo "configure:11829: checking for dsegv_" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11855: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_dsegv_=yes" else @@ -11844,13 +11878,13 @@ if test $lapack_ok = no; then save_libs="$LIBS"; LIBS="$BLASLIB $MATHLIB $LIBS" save_LDFLAGS="$LDFLAGS"; LDFLAGS="$LAPACKLIB $LDFLAGS" echo $ac_n "checking for desgv_ in -llapack""... $ac_c" 1>&6 -echo "configure:11848: checking for desgv_ in -llapack" >&5 +echo "configure:11882: checking for desgv_ in -llapack" >&5 ac_lib_var=`echo lapack'_'desgv_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-llapack $FLIBS $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11899: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11893,13 +11927,13 @@ LDFLAGS="$LAPACKLIB $LDFLAGS" echo $ac_n "checking for dgesv_ in -llapack""... $ac_c" 1>&6 -echo "configure:11897: checking for dgesv_ in -llapack" >&5 +echo "configure:11931: checking for dgesv_ in -llapack" >&5 ac_lib_var=`echo lapack'_'dgesv_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-llapack $BLASLIB $MATHLIB $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11948: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11929,13 +11963,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dgesv_ in -llapack""... $ac_c" 1>&6 -echo "configure:11933: checking for dgesv_ in -llapack" >&5 +echo "configure:11967: checking for dgesv_ in -llapack" >&5 ac_lib_var=`echo lapack'_'dgesv_ | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-llapack $BLASLIB $MATHLIB -lg2c $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:11984: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -11998,11 +12032,176 @@ fi # $USE_BLAS # Done checking LAPACK +# libsvm option +LIBSVM_INC= +LIBSVM_LIB= +USE_LIBSVM= + + +echo $ac_n "checking whether to use libsvm""... $ac_c" 1>&6 +echo "configure:12043: checking whether to use libsvm" >&5 +echo "$ac_t"""$with_libsvm"" 1>&6 +case "$with_libsvm" in + "no") USE_LIBSVM= ;; + "yes") USE_LIBSVM="1" ;; + *) { echo "configure: error: *** You must answer yes or no." 1>&2; exit 1; } ;; +esac + + + +if test -n "$USE_LIBSVM"; then + +echo $ac_n "checking for location of libsvm includes""... $ac_c" 1>&6 +echo "configure:12056: checking for location of libsvm includes" >&5 +case "$with_libsvm_includes" in +y | ye | yes | n | no) + { echo "configure: error: *** You must supply a directory to --with-libsvm-includes." 1>&2; exit 1; } + ;; +esac +echo "$ac_t""$with_libsvm_includes" 1>&6 + +if test -n "$with_libsvm_includes" ; then + for dir in $with_libsvm_includes; do + if test -d "$dir"; then + LIBSVM_INC="$LIBSVM_INC -I$dir" + else + { echo "configure: error: *** libsvm includes directory $dir does not exist." 1>&2; exit 1; } + fi + done +fi + + +ac_save_cppflags="$CPPFLAGS" +CPPFLAGS="$LIBSVM_INC $CPPFLAGS" +for ac_hdr in libsvm/svm.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:12081: checking for $ac_hdr" >&5 + +cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:12089: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +{ echo "configure: error: *** Unable to locate libsvm includes." 1>&2; exit 1; } + +fi +done + +CPPFLAGS=$ac_save_cppflags + + +echo $ac_n "checking for location of libsvm library""... $ac_c" 1>&6 +echo "configure:12120: checking for location of libsvm library" >&5 +case "$with_libsvm_libs" in +y | ye | yes | n | no) + { echo "configure: error: *** You must supply a directory to --with-libsvm-libs." 1>&2; exit 1; } + ;; +esac +echo "$ac_t""$with_libsvm_libs" 1>&6 + +if test -n "$with_libsvm_libs"; then + for dir in $with_libsvm_libs; do + if test -d "$dir"; then + LIBSVM_LIB="$LIBSVM_LIB -L$dir" + else + { echo "configure: error: *** libsvm library directory $dir does not exist." 1>&2; exit 1; } + fi + done +fi + + +ac_save_ldflags="$LDFLAGS" +LDFLAGS="$LIBSVM_LIB $LDFLAGS" + + +echo $ac_n "checking for svm_load_model in -lsvm""... $ac_c" 1>&6 +echo "configure:12144: checking for svm_load_model in -lsvm" >&5 +ac_lib_var=`echo svm'_'svm_load_model | sed 'y%./+-%__p_%'` + +ac_save_LIBS="$LIBS" +LIBS="-lsvm $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBSVM_LIB="$LIBSVM_LIB -lsvm " +else + echo "$ac_t""no" 1>&6 + +LDFLAGS=${ac_save_ldflags} + + { echo "configure: error: *** Unable to locate libsvm library." 1>&2; exit 1; } + + +fi + + + +LDFLAGS=${ac_save_ldflags} + + cat >> confdefs.h <<\EOF +#define HAVE_LIBSVM 1 +EOF + +fi + + + + +# Done with libsvm + # Enable Cairo display driver option echo $ac_n "checking whether to use Cairo""... $ac_c" 1>&6 -echo "configure:12006: checking whether to use Cairo" >&5 +echo "configure:12205: checking whether to use Cairo" >&5 echo "$ac_t"""$with_cairo"" 1>&6 case "$with_cairo" in "no") USE_CAIRO= ;; @@ -12034,7 +12233,7 @@ CAIROINC=`$PKG_CONFIG --cflags $cairo` echo $ac_n "checking for location of cairo includes""... $ac_c" 1>&6 -echo "configure:12038: checking for location of cairo includes" >&5 +echo "configure:12237: checking for location of cairo includes" >&5 case "$with_cairo_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-cairo-includes." 1>&2; exit 1; } @@ -12060,15 +12259,15 @@ for ac_hdr in cairo.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:12064: checking for $ac_hdr" >&5 +echo "configure:12263: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:12072: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:12271: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -12104,7 +12303,7 @@ CAIROLIB=`$PKG_CONFIG --libs $cairo` echo $ac_n "checking for location of cairo library""... $ac_c" 1>&6 -echo "configure:12108: checking for location of cairo library" >&5 +echo "configure:12307: checking for location of cairo library" >&5 case "$with_cairo_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-cairo-libs." 1>&2; exit 1; } @@ -12124,7 +12323,7 @@ fi echo $ac_n "checking for cairo linking flags""... $ac_c" 1>&6 -echo "configure:12128: checking for cairo linking flags" >&5 +echo "configure:12327: checking for cairo linking flags" >&5 case "$with_cairo_ldflags" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-cairo-ldflags." 1>&2; exit 1; } @@ -12140,10 +12339,10 @@ ac_save_ldflags="$LDFLAGS" LIBS=" $CAIROLIB $LIBS" LDFLAGS=" $LDFLAGS" echo $ac_n "checking for cairo_create""... $ac_c" 1>&6 -echo "configure:12144: checking for cairo_create" >&5 +echo "configure:12343: checking for cairo_create" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12369: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_cairo_create=yes" else @@ -12200,10 +12399,10 @@ ac_save_ldflags="$LDFLAGS" LIBS=" $CAIROLIB $LIBS" LDFLAGS=" $LDFLAGS" echo $ac_n "checking for cairo_xlib_surface_create_with_xrender_format""... $ac_c" 1>&6 -echo "configure:12204: checking for cairo_xlib_surface_create_with_xrender_format" >&5 +echo "configure:12403: checking for cairo_xlib_surface_create_with_xrender_format" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12429: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_cairo_xlib_surface_create_with_xrender_format=yes" else @@ -12259,10 +12458,10 @@ ac_save_ldflags="$LDFLAGS" LIBS=" $CAIROLIB $LIBS" LDFLAGS=" $LDFLAGS" echo $ac_n "checking for cairo_xlib_surface_get_xrender_format""... $ac_c" 1>&6 -echo "configure:12263: checking for cairo_xlib_surface_get_xrender_format" >&5 +echo "configure:12462: checking for cairo_xlib_surface_get_xrender_format" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12488: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_cairo_xlib_surface_get_xrender_format=yes" else @@ -12327,7 +12526,7 @@ fi # $USE_CAIRO echo $ac_n "checking whether to use FreeType""... $ac_c" 1>&6 -echo "configure:12331: checking whether to use FreeType" >&5 +echo "configure:12530: checking whether to use FreeType" >&5 echo "$ac_t"""$with_freetype"" 1>&6 case "$with_freetype" in "no") USE_FREETYPE= ;; @@ -12348,7 +12547,7 @@ FTINC=`$PKG_CONFIG --cflags freetype2` echo $ac_n "checking for location of FreeType includes""... $ac_c" 1>&6 -echo "configure:12352: checking for location of FreeType includes" >&5 +echo "configure:12551: checking for location of FreeType includes" >&5 case "$with_freetype_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-freetype-includes." 1>&2; exit 1; } @@ -12374,15 +12573,15 @@ for ac_hdr in ft2build.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:12378: checking for $ac_hdr" >&5 +echo "configure:12577: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:12386: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:12585: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -12418,7 +12617,7 @@ FTLIB=`$PKG_CONFIG --libs freetype2` echo $ac_n "checking for location of FreeType library""... $ac_c" 1>&6 -echo "configure:12422: checking for location of FreeType library" >&5 +echo "configure:12621: checking for location of FreeType library" >&5 case "$with_freetype_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-freetype-libs." 1>&2; exit 1; } @@ -12443,13 +12642,13 @@ LDFLAGS="$FTLIB $LDFLAGS" echo $ac_n "checking for FT_Init_FreeType in -lfreetype""... $ac_c" 1>&6 -echo "configure:12447: checking for FT_Init_FreeType in -lfreetype" >&5 +echo "configure:12646: checking for FT_Init_FreeType in -lfreetype" >&5 ac_lib_var=`echo freetype'_'FT_Init_FreeType | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lfreetype $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12663: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -12501,7 +12700,7 @@ fi # $USE_FREETYPE echo $ac_n "checking whether to use NLS""... $ac_c" 1>&6 -echo "configure:12505: checking whether to use NLS" >&5 +echo "configure:12704: checking whether to use NLS" >&5 echo "$ac_t"""$with_nls"" 1>&6 case "$with_nls" in "no") USE_NLS= ;; @@ -12521,10 +12720,10 @@ EOF echo $ac_n "checking for gettext""... $ac_c" 1>&6 -echo "configure:12525: checking for gettext" >&5 +echo "configure:12724: checking for gettext" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12750: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gettext=yes" else @@ -12565,13 +12764,13 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for gettext in -lintl""... $ac_c" 1>&6 -echo "configure:12569: checking for gettext in -lintl" >&5 +echo "configure:12768: checking for gettext in -lintl" >&5 ac_lib_var=`echo intl'_'gettext | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lintl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12785: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -12617,7 +12816,7 @@ fi echo $ac_n "checking whether to use C++""... $ac_c" 1>&6 -echo "configure:12621: checking whether to use C++" >&5 +echo "configure:12820: checking whether to use C++" >&5 echo "$ac_t"""$with_cxx"" 1>&6 case "$with_cxx" in "no") USE_CXX= ;; @@ -12633,7 +12832,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:12637: checking for $ac_word" >&5 +echo "configure:12836: checking for $ac_word" >&5 if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. @@ -12662,7 +12861,7 @@ test -n "$CXX" || CXX="gcc" echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:12666: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo "configure:12865: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 ac_ext=C # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -12673,12 +12872,12 @@ cross_compiling=$ac_cv_prog_cxx_cross cat > conftest.$ac_ext << EOF -#line 12677 "configure" +#line 12876 "configure" #include "confdefs.h" int main(){return(0);} EOF -if { (eval echo configure:12682: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:12881: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cxx_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -12704,19 +12903,19 @@ if test $ac_cv_prog_cxx_works = no; then { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:12708: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:12907: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 cross_compiling=$ac_cv_prog_cxx_cross echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 -echo "configure:12713: checking whether we are using GNU C++" >&5 +echo "configure:12912: checking whether we are using GNU C++" >&5 cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:12919: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gxx=yes else ac_cv_prog_gxx=no @@ -12734,7 +12933,7 @@ ac_test_CXXFLAGS="${CXXFLAGS+set}" ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS= echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 -echo "configure:12738: checking whether ${CXX-g++} accepts -g" >&5 +echo "configure:12937: checking whether ${CXX-g++} accepts -g" >&5 echo 'void f(){}' > conftest.cc if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then @@ -12762,57 +12961,6 @@ else fi fi -for ac_declaration in \ - ''\ - '#include ' \ - 'extern "C" void std::exit (int) throw (); using std::exit;' \ - 'extern "C" void std::exit (int); using std::exit;' \ - 'extern "C" void exit (int) throw ();' \ - 'extern "C" void exit (int);' \ - 'void exit (int);' -do - cat > conftest.$ac_ext < -$ac_declaration -int main() { -exit (42); -; return 0; } -EOF -if { (eval echo configure:12784: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - : -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - continue -fi -rm -f conftest* - cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - break -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 -fi -rm -f conftest* -done -if test -n "$ac_declaration"; then - echo '#ifdef __cplusplus' >>confdefs.h - echo $ac_declaration >>confdefs.h - echo '#endif' >>confdefs.h -fi - - else CXX= CXXFLAGS= @@ -12826,7 +12974,7 @@ fi echo $ac_n "checking whether to use openDWG""... $ac_c" 1>&6 -echo "configure:12830: checking whether to use openDWG" >&5 +echo "configure:12978: checking whether to use openDWG" >&5 echo "$ac_t"""$with_opendwg"" 1>&6 case "$with_opendwg" in "no") USE_OPENDWG= ;; @@ -12846,7 +12994,7 @@ if test -n "${USE_OPENDWG}"; then echo $ac_n "checking for location of openDGW includes""... $ac_c" 1>&6 -echo "configure:12850: checking for location of openDGW includes" >&5 +echo "configure:12998: checking for location of openDGW includes" >&5 case "$with_opendwg_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-opendwg-includes." 1>&2; exit 1; } @@ -12872,15 +13020,15 @@ for ac_hdr in ad2.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:12876: checking for $ac_hdr" >&5 +echo "configure:13024: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:12884: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:13032: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -12914,7 +13062,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of openDWG library""... $ac_c" 1>&6 -echo "configure:12918: checking for location of openDWG library" >&5 +echo "configure:13066: checking for location of openDWG library" >&5 case "$with_opendwg_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-opendwg-libs." 1>&2; exit 1; } @@ -12955,7 +13103,7 @@ fi # $USE_OPENDWG echo $ac_n "checking whether to use POSIX threads""... $ac_c" 1>&6 -echo "configure:12959: checking whether to use POSIX threads" >&5 +echo "configure:13107: checking whether to use POSIX threads" >&5 echo "$ac_t"""$with_pthread"" 1>&6 case "$with_pthread" in "no") USE_PTHREAD= ;; @@ -12975,7 +13123,7 @@ if test -n "$USE_PTHREAD"; then echo $ac_n "checking for location of POSIX threads includes""... $ac_c" 1>&6 -echo "configure:12979: checking for location of POSIX threads includes" >&5 +echo "configure:13127: checking for location of POSIX threads includes" >&5 case "$with_pthread_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-pthread-includes." 1>&2; exit 1; } @@ -13001,15 +13149,15 @@ for ac_hdr in pthread.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:13005: checking for $ac_hdr" >&5 +echo "configure:13153: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:13013: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:13161: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -13043,7 +13191,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of POSIX threads library""... $ac_c" 1>&6 -echo "configure:13047: checking for location of POSIX threads library" >&5 +echo "configure:13195: checking for location of POSIX threads library" >&5 case "$with_pthread_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-pthread-libs." 1>&2; exit 1; } @@ -13068,10 +13216,10 @@ ac_save_ldflags="$LDFLAGS" LIBS=" $LIBS" LDFLAGS=" $LDFLAGS" echo $ac_n "checking for pthread_create""... $ac_c" 1>&6 -echo "configure:13072: checking for pthread_create" >&5 +echo "configure:13220: checking for pthread_create" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13246: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_pthread_create=yes" else @@ -13121,13 +13269,13 @@ LDFLAGS="$PTHREADLIBPATH $LDFLAGS" echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6 -echo "configure:13125: checking for pthread_create in -lpthread" >&5 +echo "configure:13273: checking for pthread_create in -lpthread" >&5 ac_lib_var=`echo pthread'_'pthread_create | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lpthread $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13290: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -13188,7 +13336,7 @@ fi # $USE_PTHREAD echo $ac_n "checking whether to use OpenMP""... $ac_c" 1>&6 -echo "configure:13192: checking whether to use OpenMP" >&5 +echo "configure:13340: checking whether to use OpenMP" >&5 echo "$ac_t"""$with_openmp"" 1>&6 case "$with_openmp" in "no") USE_OPENMP= ;; @@ -13209,7 +13357,7 @@ if test -n "$USE_OPENMP"; then echo $ac_n "checking for location of OpenMP includes""... $ac_c" 1>&6 -echo "configure:13213: checking for location of OpenMP includes" >&5 +echo "configure:13361: checking for location of OpenMP includes" >&5 case "$with_openmp_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-openmp-includes." 1>&2; exit 1; } @@ -13235,15 +13383,15 @@ for ac_hdr in omp.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:13239: checking for $ac_hdr" >&5 +echo "configure:13387: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:13247: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:13395: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -13281,7 +13429,7 @@ CPPFLAGS=$ac_save_cppflags echo $ac_n "checking for location of OpenMP library""... $ac_c" 1>&6 -echo "configure:13285: checking for location of OpenMP library" >&5 +echo "configure:13433: checking for location of OpenMP library" >&5 case "$with_openmp_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-openmp-libs." 1>&2; exit 1; } @@ -13306,10 +13454,10 @@ ac_save_ldflags="$LDFLAGS" LIBS=" $LIBS" LDFLAGS=" $LDFLAGS" echo $ac_n "checking for GOMP_parallel_start""... $ac_c" 1>&6 -echo "configure:13310: checking for GOMP_parallel_start" >&5 +echo "configure:13458: checking for GOMP_parallel_start" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13484: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_GOMP_parallel_start=yes" else @@ -13359,13 +13507,13 @@ LDFLAGS="$OMPLIBPATH $LDFLAGS" echo $ac_n "checking for GOMP_parallel_start in -lgomp""... $ac_c" 1>&6 -echo "configure:13363: checking for GOMP_parallel_start in -lgomp" >&5 +echo "configure:13511: checking for GOMP_parallel_start in -lgomp" >&5 ac_lib_var=`echo gomp'_'GOMP_parallel_start | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lgomp $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13528: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -13449,7 +13597,7 @@ fi # $USE_OPENMP echo $ac_n "checking whether to use OpenCL""... $ac_c" 1>&6 -echo "configure:13453: checking whether to use OpenCL" >&5 +echo "configure:13601: checking whether to use OpenCL" >&5 echo "$ac_t"""$with_opencl"" 1>&6 case "$with_opencl" in "no") USE_OPENCL= ;; @@ -13469,7 +13617,7 @@ if test -n "$USE_OPENCL"; then echo $ac_n "checking for location of OpenCL includes""... $ac_c" 1>&6 -echo "configure:13473: checking for location of OpenCL includes" >&5 +echo "configure:13621: checking for location of OpenCL includes" >&5 case "$with_opencl_includes" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-opencl-includes." 1>&2; exit 1; } @@ -13496,15 +13644,15 @@ for ac_hdr in OpenCL/opencl.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:13500: checking for $ac_hdr" >&5 +echo "configure:13648: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:13508: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:13656: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -13544,10 +13692,10 @@ ac_save_ldflags="$LDFLAGS" LIBS="-framework OpenCL $LIBS" LDFLAGS=" $LDFLAGS" echo $ac_n "checking for clGetPlatformInfo""... $ac_c" 1>&6 -echo "configure:13548: checking for clGetPlatformInfo" >&5 +echo "configure:13696: checking for clGetPlatformInfo" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13722: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_clGetPlatformInfo=yes" else @@ -13609,15 +13757,15 @@ for ac_hdr in CL/cl.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:13613: checking for $ac_hdr" >&5 +echo "configure:13761: checking for $ac_hdr" >&5 cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:13621: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:13769: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -13650,7 +13798,7 @@ CPPFLAGS=$ac_save_cppflags # With OpenCL library directory echo $ac_n "checking for location of OpenCL library""... $ac_c" 1>&6 -echo "configure:13654: checking for location of OpenCL library" >&5 +echo "configure:13802: checking for location of OpenCL library" >&5 case "$with_opencl_libs" in y | ye | yes | n | no) { echo "configure: error: *** You must supply a directory to --with-opencl-libs." 1>&2; exit 1; } @@ -13674,13 +13822,13 @@ LDFLAGS="$OCLLIBPATH $LDFLAGS" echo $ac_n "checking for clGetPlatformInfo in -lOpenCL""... $ac_c" 1>&6 -echo "configure:13678: checking for clGetPlatformInfo in -lOpenCL" >&5 +echo "configure:13826: checking for clGetPlatformInfo in -lOpenCL" >&5 ac_lib_var=`echo OpenCL'_'clGetPlatformInfo | sed 'y%./+-%__p_%'` ac_save_LIBS="$LIBS" LIBS="-lOpenCL $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:13843: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -13751,7 +13899,7 @@ fi fi echo $ac_n "checking for special C compiler options needed for large files""... $ac_c" 1>&6 -echo "configure:13755: checking for special C compiler options needed for large files" >&5 +echo "configure:13903: checking for special C compiler options needed for large files" >&5 ac_cv_sys_largefile_CC=no largefile_cc_opt="" @@ -13759,7 +13907,7 @@ ac_cv_sys_largefile_CC=no # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat > conftest.$ac_ext < /* Check that off_t can represent 2**63 - 1 correctly. @@ -13775,7 +13923,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13779: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:13927: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 @@ -13784,7 +13932,7 @@ else ac_save_CC="${CC-cc}" CC="$CC -n32" cat > conftest.$ac_ext < /* Check that off_t can represent 2**63 - 1 correctly. @@ -13800,7 +13948,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13804: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:13952: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sys_largefile_CC=' -n32' else @@ -13827,11 +13975,11 @@ echo "$ac_t""$ac_cv_sys_largefile_CC" 1>&6 fi echo $ac_n "checking for _FILE_OFFSET_BITS value needed for large files""... $ac_c" 1>&6 -echo "configure:13831: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +echo "configure:13979: checking for _FILE_OFFSET_BITS value needed for large files" >&5 ac_cv_sys_file_offset_bits=no cat > conftest.$ac_ext < /* Check that off_t can represent 2**63 - 1 correctly. @@ -13847,14 +13995,14 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13851: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:13999: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* cat > conftest.$ac_ext < @@ -13872,7 +14020,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13876: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:14024: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sys_file_offset_bits=64 else @@ -13898,11 +14046,11 @@ EOF fi echo $ac_n "checking for _LARGE_FILES value needed for large files""... $ac_c" 1>&6 -echo "configure:13902: checking for _LARGE_FILES value needed for large files" >&5 +echo "configure:14050: checking for _LARGE_FILES value needed for large files" >&5 ac_cv_sys_large_files=no cat > conftest.$ac_ext < /* Check that off_t can represent 2**63 - 1 correctly. @@ -13918,14 +14066,14 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13922: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:14070: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* cat > conftest.$ac_ext < @@ -13943,7 +14091,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:13947: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:14095: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sys_large_files=1 else @@ -13969,25 +14117,25 @@ EOF fi echo $ac_n "checking for _LARGEFILE_SOURCE value needed for large files""... $ac_c" 1>&6 -echo "configure:13973: checking for _LARGEFILE_SOURCE value needed for large files" >&5 +echo "configure:14121: checking for _LARGEFILE_SOURCE value needed for large files" >&5 ac_cv_sys_largefile_source=no cat > conftest.$ac_ext < int main() { return !fseeko; ; return 0; } EOF -if { (eval echo configure:13984: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:14132: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* cat > conftest.$ac_ext < @@ -13996,7 +14144,7 @@ int main() { return !fseeko; ; return 0; } EOF -if { (eval echo configure:14000: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:14148: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sys_largefile_source=1 else @@ -14028,25 +14176,25 @@ EOF ac_save_cflags=${CFLAGS} CFLAGS="$LFS_CFLAGS ${ac_save_cflags}" echo $ac_n "checking for _LARGEFILE_SOURCE value needed for large files""... $ac_c" 1>&6 -echo "configure:14032: checking for _LARGEFILE_SOURCE value needed for large files" >&5 +echo "configure:14180: checking for _LARGEFILE_SOURCE value needed for large files" >&5 ac_cv_sys_largefile_source=no cat > conftest.$ac_ext < int main() { return !fseeko; ; return 0; } EOF -if { (eval echo configure:14043: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:14191: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* cat > conftest.$ac_ext < @@ -14055,7 +14203,7 @@ int main() { return !fseeko; ; return 0; } EOF -if { (eval echo configure:14059: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:14207: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sys_largefile_source=1 else @@ -14085,18 +14233,18 @@ EOF # If you want fseeko and ftello with glibc, upgrade to a fixed glibc. echo $ac_n "checking for fseeko""... $ac_c" 1>&6 -echo "configure:14089: checking for fseeko" >&5 +echo "configure:14237: checking for fseeko" >&5 ac_cv_func_fseeko=no cat > conftest.$ac_ext < int main() { return fseeko && fseeko (stdin, 0, 0); ; return 0; } EOF -if { (eval echo configure:14100: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:14248: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_func_fseeko=yes else @@ -14113,10 +14261,10 @@ EOF fi echo $ac_n "checking if system supports Large Files at all""... $ac_c" 1>&6 -echo "configure:14117: checking if system supports Large Files at all" >&5 +echo "configure:14265: checking if system supports Large Files at all" >&5 cat > conftest.$ac_ext < #include @@ -14148,7 +14296,7 @@ return !ftello; #endif ; return 0; } EOF -if { (eval echo configure:14152: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:14300: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_largefiles=yes else @@ -14421,6 +14569,9 @@ s%@BLASLIB@%$BLASLIB%g s%@BLASINC@%$BLASINC%g s%@LAPACKLIB@%$LAPACKLIB%g s%@LAPACKINC@%$LAPACKINC%g +s%@LIBSVM_INC@%$LIBSVM_INC%g +s%@LIBSVM_LIB@%$LIBSVM_LIB%g +s%@USE_LIBSVM@%$USE_LIBSVM%g s%@CAIRO_HAS_XRENDER@%$CAIRO_HAS_XRENDER%g s%@CAIRO_HAS_XRENDER_SURFACE@%$CAIRO_HAS_XRENDER_SURFACE%g s%@CAIROINC@%$CAIROINC%g @@ -14752,6 +14903,8 @@ echo " Large File support (LFS): `if test -n "${USE_LARGEFILES}" ; then echo echo " libLAS support: `if test -n "${USE_LIBLAS}" ; then echo yes ; else echo no ; fi`" +echo " Libsvm support: `if test -n "${USE_LIBSVM}" ; then echo yes ; else echo no ; fi`" + echo " MySQL support: `if test -n "${USE_MYSQL}" ; then echo yes ; else echo no ; fi`" echo " NetCDF support: `if test -n "${USE_NETCDF}" ; then echo yes ; else echo no ; fi`" From b8622d94bfedde4910a2664facf5f2b4f24a861a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 10 Sep 2021 12:51:27 +0300 Subject: [PATCH 018/123] i.svm.train: move from element to dir in library calls --- imagery/i.svm.train/fill.c | 2 ++ imagery/i.svm.train/main.c | 15 ++++++++++----- imagery/i.svm.train/testsuite/test_i_svm_train.py | 4 ++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/imagery/i.svm.train/fill.c b/imagery/i.svm.train/fill.c index 1aa3ac84ac4..1c351c53873 100644 --- a/imagery/i.svm.train/fill.c +++ b/imagery/i.svm.train/fill.c @@ -109,6 +109,8 @@ void fill_problem(const char *name_labels, const char *mapset_labels, Rast_close(fd_bands[band]); G_free(buf_bands[band]); } + G_free(fd_bands); + G_free(buf_bands); G_percent(1, 1, 1); G_percent_reset(); } diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index c14c6405aa4..96de984a754 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -11,8 +11,8 @@ * License (>=v2). Read the file COPYING that comes with GRASS * for details. * - * Development supported from science funding of - * University of Latvia (2020/2021). + * Development of this module was supported from + * science funding of University of Latvia (2020/2021). * *****************************************************************************/ #include @@ -364,6 +364,7 @@ int main(int argc, char *argv[]) group_ref.file[n].name, group_ref.file[n].mapset); } + /* Pass libsvm messages through GRASS */ svm_set_print_string_function(&print_func); /* Fill svm_problem struct with training data */ @@ -386,9 +387,9 @@ int main(int argc, char *argv[]) /* Write out training results */ G_verbose_message("Writing out trained SVM"); /* This is a specific case as file is not written by GRASS but - * by libsvm and thus "normal" GRASS lib functions can not be used. */ - I__make_signatures_element(I_SIGFILE_TYPE_LIBSVM); - I__get_signatures_element(sigfile_dir, I_SIGFILE_TYPE_LIBSVM); + by libsvm and thus "normal" GRASS lib functions can not be used. */ + I_make_signatures_dir(I_SIGFILE_TYPE_LIBSVM); + I_get_signatures_dir(sigfile_dir, I_SIGFILE_TYPE_LIBSVM); /* G_fopen_new_misc should create a directory for later use */ misc_file = G_fopen_new_misc(sigfile_dir, "version", name_sigfile); if (!misc_file) @@ -404,6 +405,7 @@ int main(int argc, char *argv[]) G_fatal_error(_("Unable to write trained model to file '%s'. Error code: %d"), out_path, out_status); } + svm_free_and_destroy_model(&model); /* Write out band reference info */ misc_file = G_fopen_new_misc(sigfile_dir, "bandref", name_sigfile); if (!misc_file) @@ -413,6 +415,7 @@ int main(int argc, char *argv[]) fprintf(misc_file, "%s\n", bandrefs[n]); } fclose(misc_file); + G_free(bandrefs); /* Copy CATs file. Will be used for prediction result maps */ G_verbose_message("Copying category information"); @@ -421,6 +424,7 @@ int main(int argc, char *argv[]) G_file_name(in_path, "cats", name_labels, mapset_labels); G_file_name_misc(out_path, sigfile_dir, "cats", name_sigfile, G_mapset()); + /* It is OK to call G_copy if source file doesn't exist */ G_copy_file(in_path, out_path); } @@ -431,6 +435,7 @@ int main(int argc, char *argv[]) G_file_name(in_path, "colr", name_labels, mapset_labels); G_file_name_misc(out_path, sigfile_dir, "colr", name_sigfile, G_mapset()); + /* It is OK to call G_copy if source file doesn't exist */ G_copy_file(in_path, out_path); } diff --git a/imagery/i.svm.train/testsuite/test_i_svm_train.py b/imagery/i.svm.train/testsuite/test_i_svm_train.py index 3e3a6122900..3086013b332 100644 --- a/imagery/i.svm.train/testsuite/test_i_svm_train.py +++ b/imagery/i.svm.train/testsuite/test_i_svm_train.py @@ -27,7 +27,7 @@ ) from grass.lib.imagery import ( I_SIGFILE_TYPE_LIBSVM, - I__get_signatures_element, + I_get_signatures_dir, I_signatures_remove, ) @@ -155,7 +155,7 @@ def test_creation_of_misc_files(self): """Validate creation of category, history and colour files""" sigfile = grass.tempname(10) csigdir = ctypes.create_string_buffer(GNAME_MAX) - I__get_signatures_element(csigdir, I_SIGFILE_TYPE_LIBSVM) + I_get_signatures_dir(csigdir, I_SIGFILE_TYPE_LIBSVM) sigdir = utils.decode(csigdir.value) isvm = SimpleModule( "i.svm.train", From c7364518c68015036e6a746735fc213bc13fac5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Thu, 23 Sep 2021 19:36:04 +0300 Subject: [PATCH 019/123] i.svm: prediction code fixes, tests and GUI support --- gui/wxpython/gui_core/gselect.py | 3 + imagery/i.svm.predict/i.svm.predict.html | 71 ++++++ imagery/i.svm.predict/main.c | 166 +++++++++----- .../testsuite/test_i_svm_predict.py | 205 ++++++++++++++++++ imagery/i.svm.train/fill.c | 3 +- imagery/i.svm.train/i.svm.train.html | 30 +-- .../i.svm.train/testsuite/test_i_svm_train.py | 41 +++- 7 files changed, 443 insertions(+), 76 deletions(-) create mode 100644 imagery/i.svm.predict/i.svm.predict.html create mode 100644 imagery/i.svm.predict/testsuite/test_i_svm_predict.py diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index 6fdfd95b124..a2be8563e56 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -62,6 +62,7 @@ from grass.lib.imagery import ( I_SIGFILE_TYPE_SIG, I_SIGFILE_TYPE_SIGSET, + I_SIGFILE_TYPE_LIBSVM, I_signatures_list_by_type, I_free_signatures_list, ) @@ -2819,6 +2820,8 @@ def __init__( sig_type = I_SIGFILE_TYPE_SIG elif element == "signatures/sigset": sig_type = I_SIGFILE_TYPE_SIGSET + elif element == "signatures/libsvm": + sig_type = I_SIGFILE_TYPE_LIBSVM items = [] if sig_type is not None: if mapsets: diff --git a/imagery/i.svm.predict/i.svm.predict.html b/imagery/i.svm.predict/i.svm.predict.html new file mode 100644 index 00000000000..c8f3db53d75 --- /dev/null +++ b/imagery/i.svm.predict/i.svm.predict.html @@ -0,0 +1,71 @@ +

DESCRIPTION

+ +

i.svm.predict predicts values with a Support Vector Machine (SVM) +and stores them in a raster file. Predictions are based on a signature file +generated with i.svm.train. +

+ +

NOTES

+ +

i.svm.train internally is using the libsvm. For introduction +into value prediction or estimation with libsvm, see +a +Practical Guide to Support Vector Classification by +Chih-Wei Hsu, Chih-Chung Chang, and Chih-Jen Lin.

+ +

It is strongly suggested to have semantic labels set for each raster +map in the training data (feature value) and in value prediction imagery groups. +Use r.support to set semantic labels.

+ +

PERFORMANCE

+ +

Value prediction is done cell by cell and thus memory consumption +should be constant.

+ +

EXAMPLE

+ +

This is the second part of classification process. See +i.svm.train for the first part.

+ +

Predict land use classes form a LANDSAT scene from +October of 2002 with a SVM trained on a 1996 land +use map landuse96_28m.

+
+i.svm.predict group=lsat7_2002 subgroup=lsat7_2002\
+    signaturefile=landuse96_rnd_points output=pred_landuse_2002
+
+ +

SEE ALSO

+ + +Train SVM: i.svm.train
+Set semantic labels: r.support
+Other classification modules: i.maxlik, +i.smap +

+Libsvm home page: LIBSVM - A +Library for Support Vector Machines + +

REFERENCES

+ +

Please cite both - libsvm and i.svm.

+
    +
  • + For i.svm.* modules:
    + TODO. +
  • +
  • + For libsvm:
    + C.-C. Chang and C.-J. Lin. LIBSVM : a library for support vector machines. + ACM Transactions on Intelligent Systems and Technology, 2:27:1--27:27, 2011. +
  • +
+ +

AUTHORS

+ +Maris Nartiss, University of Latvia. + + diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c index b7d530b4037..c3000a87070 100644 --- a/imagery/i.svm.predict/main.c +++ b/imagery/i.svm.predict/main.c @@ -5,15 +5,19 @@ * AUTHOR(S): Maris Nartiss - maris.gis gmail.com * PURPOSE: Predicts values with Support Vector Machine classifier * - * COPYRIGHT: (C) 2020 by Maris Nartiss and the GRASS Development Team + * COPYRIGHT: (C) 2021 by Maris Nartiss and the GRASS Development Team * * This program is free software under the GNU General Public * License (>=v2). Read the file COPYING that comes with GRASS * for details. * + * Development of this module was supported from + * science funding of University of Latvia (2020/2021). + * *****************************************************************************/ #include #include +#include #include @@ -22,6 +26,9 @@ #include #include +#define XSTR(s) STR(s) +#define STR(s) #s + /* LIBSVM message wrapper */ void print_func(const char *s) @@ -36,21 +43,23 @@ int main(int argc, char *argv[]) struct Option *opt_group, *opt_subgroup, *opt_sigfile, *opt_values; struct Option *opt_svm_cache_size; - char name_values[GNAME_MAX], name_group[GNAME_MAX], - name_subgroup[GNAME_MAX]; - const char *name_sigfile, *mapset_sigfile; - char mapset_group[GMAPSET_MAX], mapset_subgroup[GMAPSET_MAX], - mapset_values[GMAPSET_MAX]; + char name_values[GNAME_MAX], name_sigfile[GNAME_MAX]; + char name_group[GNAME_MAX], name_subgroup[GNAME_MAX]; + char mapset_values[GMAPSET_MAX], mapset_sigfile[GMAPSET_MAX]; + char mapset_group[GMAPSET_MAX], mapset_subgroup[GMAPSET_MAX]; char sigfile_dir[GPATH_MAX], model_file[GPATH_MAX]; - char in_path[GPATH_MAX], out_path[GPATH_MAX]; - struct Ref band_ref; + struct Ref group_ref; + char **names_ordered, **mapsets_ordered; + const char **bandrefs_group, **bandrefs_svm; + char bandref[GNAME_MAX]; + int bandref_count = 0, bandref_match_count = 0; struct svm_model *model; struct History history; - FILE *hist_file; - char hist_line[4096]; /* history lines are limited to 4096 */ + FILE *misc_file; + int sigfile_version; G_gisinit(argv[0]); @@ -60,7 +69,7 @@ int main(int argc, char *argv[]) G_add_keyword(_("classification")); G_add_keyword(_("prediction")); G_add_keyword(_("regression")); - module->description = _("Predict with SVM"); + module->description = _("Predict with a SVM"); opt_group = G_define_standard_option(G_OPT_I_GROUP); /* GTC: SVM prediction input */ @@ -70,12 +79,12 @@ int main(int argc, char *argv[]) opt_subgroup->required = NO; opt_sigfile = G_define_option(); - opt_sigfile->key = "model"; + opt_sigfile->key = "signaturefile"; opt_sigfile->type = TYPE_STRING; opt_sigfile->key_desc = "name"; opt_sigfile->required = YES; - opt_sigfile->gisprompt = "old,rsvm,sigfile"; - opt_sigfile->description = _("Name trained SVM model"); + opt_sigfile->gisprompt = "old,signatures/libsvm,sigfile"; + opt_sigfile->description = _("Name of input file containing signatures"); opt_values = G_define_standard_option(G_OPT_R_OUTPUT); opt_values->required = YES; @@ -90,7 +99,6 @@ int main(int argc, char *argv[]) opt_svm_cache_size->options = "1-999999999"; opt_svm_cache_size->answer = "512"; opt_svm_cache_size->description = _("Kernel cache size in MB"); - /* opt_svm_cache_size->guisection = _("SVM options"); */ if (G_parser(argc, argv)) @@ -117,19 +125,13 @@ int main(int argc, char *argv[]) name_subgroup, name_group, mapset_group); } - name_sigfile = opt_sigfile->answer; - if (opt_subgroup->answer) - sprintf(sigfile_dir, "group%c%s%csubgroup%c%s%crsvm", HOST_DIRSEP, - name_group, HOST_DIRSEP, HOST_DIRSEP, opt_subgroup->answer, - HOST_DIRSEP); - else - sprintf(sigfile_dir, "group%c%s%crsvm", HOST_DIRSEP, name_group, - HOST_DIRSEP); - mapset_sigfile = - G_find_file2_misc(sigfile_dir, "model", name_sigfile, ""); - if (mapset_sigfile == NULL) - G_fatal_error(_("File <%s> with trained SVM model not found"), - name_sigfile); + if (G_unqualified_name + (opt_sigfile->answer, NULL, name_sigfile, mapset_sigfile) == 0) + strcpy(mapset_sigfile, G_mapset()); + if (!I_find_signature2 + (I_SIGFILE_TYPE_LIBSVM, name_sigfile, mapset_sigfile)) + G_fatal_error(_("Signature file <%s@%s> not found"), name_sigfile, + mapset_sigfile); if (G_unqualified_name (opt_values->answer, G_mapset(), name_values, mapset_values) < 0) @@ -141,18 +143,18 @@ int main(int argc, char *argv[]) /* Get bands */ if (opt_subgroup->answer) { if (!I_get_subgroup_ref2 - (name_group, opt_subgroup->answer, mapset_group, &band_ref)) { + (name_group, opt_subgroup->answer, mapset_group, &group_ref)) { G_fatal_error(_("There was an error reading subgroup <%s> in group <%s@%s>"), opt_subgroup->answer, name_group, mapset_group); } } else { - if (!I_get_group_ref2(name_group, mapset_group, &band_ref)) { + if (!I_get_group_ref2(name_group, mapset_group, &group_ref)) { G_fatal_error(_("There was an error reading group <%s@%s>"), name_group, mapset_group); } } - if (band_ref.nfiles <= 0) { + if (group_ref.nfiles <= 0) { if (opt_subgroup->answer) G_fatal_error(_("Subgroup <%s> in group <%s@%s> contains no raster maps."), opt_subgroup->answer, name_group, mapset_group); @@ -160,12 +162,69 @@ int main(int argc, char *argv[]) G_fatal_error(_("Group <%s@%s> contains no raster maps."), name_group, mapset_group); } + bandrefs_group = G_malloc(group_ref.nfiles * sizeof(char *)); + for (int n = 0; n < group_ref.nfiles; n++) { + bandrefs_group[n] = + Rast_read_bandref(group_ref.file[n].name, + group_ref.file[n].mapset); + if (!bandrefs_group[n]) + G_fatal_error(_("Raster map <%s@%s> lacks band reference"), + group_ref.file[n].name, group_ref.file[n].mapset); + } + + I_get_signatures_dir(sigfile_dir, I_SIGFILE_TYPE_LIBSVM); + /* Reorder rasters to match the training order */ + misc_file = + G_fopen_old_misc(sigfile_dir, "version", name_sigfile, + mapset_sigfile); + if (fscanf(misc_file, "%d", &sigfile_version) != 1) { + G_fatal_error(_("Invalid signature file")); + } + fclose(misc_file); + /* Current version number is 1 */ + if (sigfile_version != 1) { + G_fatal_error(_("Invalid signature file version")); + } + /* Reorder group items to match order from the signature file */ + misc_file = + G_fopen_old_misc(sigfile_dir, "bandref", name_sigfile, + mapset_sigfile); + if (!misc_file) + G_fatal_error(_("Unable to read signature file '%s'."), name_sigfile); + names_ordered = G_malloc(group_ref.nfiles * sizeof(char *)); + mapsets_ordered = G_malloc(group_ref.nfiles * sizeof(char *)); + while (fscanf(misc_file, "%" XSTR(GNAME_MAX) "s", bandref) == 1) { + bandref_count++; + bool found = false; + + for (int n = 0; n < group_ref.nfiles; n++) { + if (bandref && strcmp(bandref, bandrefs_group[n]) == 0) { + bandref_match_count++; + found = true; + names_ordered[n] = group_ref.file[n].name; + mapsets_ordered[n] = group_ref.file[n].mapset; + break; + } + } + if (!found) + G_fatal_error(_("Imagery group does not contain a raster with a band reference '%s'"), + bandref); + } + fclose(misc_file); + if (bandref_match_count != bandref_count || + bandref_match_count != group_ref.nfiles) { + G_fatal_error(_("Unable to match all signature file bands to imagery group bands. " + "Signature band count: %d, imagery group band count: %d, band match count: %d."), + bandref_count, group_ref.nfiles, bandref_match_count); + } + + /* Pass libsvm messages through GRASS */ svm_set_print_string_function(&print_func); /* Load trained model from a file */ G_verbose_message("Reading in trained SVM"); - G_file_name_misc(model_file, sigfile_dir, "model", name_sigfile, + G_file_name_misc(model_file, sigfile_dir, "sig", name_sigfile, mapset_sigfile); model = svm_load_model(model_file); if (model == NULL) @@ -189,16 +248,15 @@ int main(int argc, char *argv[]) nrows = Rast_window_rows(); ncols = Rast_window_cols(); - buf_bands = (DCELL **) G_malloc(band_ref.nfiles * sizeof(DCELL *)); - fd_bands = (int *)G_calloc(band_ref.nfiles, sizeof(int)); - for (band = 0; band < band_ref.nfiles; band++) { + buf_bands = (DCELL **) G_malloc(group_ref.nfiles * sizeof(DCELL *)); + fd_bands = (int *)G_calloc(group_ref.nfiles, sizeof(int)); + for (band = 0; band < group_ref.nfiles; band++) { buf_bands[band] = Rast_allocate_d_buf(); fd_bands[band] = - Rast_open_old(band_ref.file[band].name, - band_ref.file[band].mapset); + Rast_open_old(names_ordered[band], mapsets_ordered[band]); } nodes = - (struct svm_node *)G_malloc(((size_t)band_ref.nfiles + 1) * + (struct svm_node *)G_malloc(((size_t)group_ref.nfiles + 1) * sizeof(struct svm_node)); /* Predict a class or calculate a value */ @@ -212,15 +270,15 @@ int main(int argc, char *argv[]) for (row = 0; row < nrows; row++) { G_percent(row, nrows, 2); - for (band = 0; band < band_ref.nfiles; band++) + for (band = 0; band < group_ref.nfiles; band++) Rast_get_d_row(fd_bands[band], &buf_bands[band][0], row); for (col = 0; col < ncols; col++) { nodes[0].index = -1; - for (band = 0; band < band_ref.nfiles; band++) { + for (band = 0; band < group_ref.nfiles; band++) { if (Rast_is_d_null_value(&buf_bands[band][col])) continue; nodes[band].index = band; - nodes[band].value = buf_bands[band][col]; + nodes[band].value = buf_bands[band][col] / 255; } /* All values where NULLs */ @@ -228,6 +286,8 @@ int main(int argc, char *argv[]) Rast_set_c_null_value(&out_row[col], 1); continue; } + /* Mark the end of values in nodes */ + nodes[group_ref.nfiles].index = -1; val = svm_predict(model, nodes); out_row[col] = (CELL) val; @@ -247,15 +307,15 @@ int main(int argc, char *argv[]) for (row = 0; row < nrows; row++) { G_percent(row, nrows, 2); - for (band = 0; band < band_ref.nfiles; band++) + for (band = 0; band < group_ref.nfiles; band++) Rast_get_d_row(fd_bands[band], &buf_bands[band][0], row); for (col = 0; col < ncols; col++) { nodes[0].index = -1; - for (band = 0; band < band_ref.nfiles; band++) { + for (band = 0; band < group_ref.nfiles; band++) { if (Rast_is_d_null_value(&buf_bands[band][col])) continue; nodes[band].index = band; - nodes[band].value = buf_bands[band][col]; + nodes[band].value = buf_bands[band][col] / 255; } /* All values where NULLs */ @@ -263,6 +323,8 @@ int main(int argc, char *argv[]) Rast_set_d_null_value(&out_row[col], 1); continue; } + /* Mark the end of values in nodes */ + nodes[group_ref.nfiles].index = -1; val = svm_predict(model, nodes); out_row[col] = val; @@ -275,7 +337,7 @@ int main(int argc, char *argv[]) /* Clean up */ Rast_close(fd_values); - for (band = 0; band < band_ref.nfiles; band++) { + for (band = 0; band < group_ref.nfiles; band++) { Rast_close(fd_bands[band]); G_free(buf_bands[band]); } @@ -284,14 +346,16 @@ int main(int argc, char *argv[]) /* Try to give full history */ G_verbose_message("Writing out history"); Rast_short_history(name_values, "raster", &history); - hist_file = + misc_file = G_fopen_old_misc(sigfile_dir, "history", name_sigfile, mapset_sigfile); - if (hist_file != NULL) { - while (G_getl(hist_line, sizeof(hist_line), hist_file) == 1) { + if (misc_file != NULL) { + char hist_line[4096]; /* history lines are limited to 4096 */ + + while (G_getl(hist_line, sizeof(hist_line), misc_file) == 1) { Rast_append_history(&history, hist_line); } - fclose(hist_file); + fclose(misc_file); } Rast_command_history(&history); if (opt_subgroup->answer) @@ -306,6 +370,8 @@ int main(int argc, char *argv[]) Rast_write_history(name_values, &history); if (svm_type != ONE_CLASS) { + char in_path[GPATH_MAX], out_path[GPATH_MAX]; + /* Copy CATs file from the original training map */ G_verbose_message("Copying category information"); G_file_name_misc(in_path, sigfile_dir, "cats", name_sigfile, @@ -322,7 +388,7 @@ int main(int argc, char *argv[]) } Rast_put_cell_title(name_values, /* GTC: A map title */ - _("Values predicted with Support Vector Machine")); + _("Values predicted with a Support Vector Machine")); exit(EXIT_SUCCESS); } diff --git a/imagery/i.svm.predict/testsuite/test_i_svm_predict.py b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py new file mode 100644 index 00000000000..32f0913ea4c --- /dev/null +++ b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py @@ -0,0 +1,205 @@ +""" +Name: i.svm.predict input & output tests +Purpose: Validates user input validation code and output generation + +Author: Maris Nartiss +Copyright: (C) 2021 by Maris Nartiss and the GRASS Development Team +Licence: This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. +""" +import os +import unittest +import ctypes + +from grass.script import core as grass +from grass.script import shutil_which +from grass.gunittest.case import TestCase +from grass.gunittest.main import test +from grass.gunittest.gmodules import SimpleModule +from grass.pygrass.gis import Mapset +from grass.pygrass import utils + +from grass.lib.gis import ( + GPATH_MAX, + GNAME_MAX, + G_file_name_misc, +) +from grass.lib.imagery import ( + I_SIGFILE_TYPE_LIBSVM, + I_get_signatures_dir, + I_signatures_remove, +) + + +class IOValidationTest(TestCase): + """Test input validation and output generation with i.svm.predict""" + + @classmethod + @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") + def setUpClass(cls): + cls.tmp_rasts = [] + cls.tmp_groups = [] + cls.mapset_name = Mapset().name + # Small region for small testing rasters + cls.use_temp_region() + cls.runModule("g.region", n=1, s=0, e=1, w=0, res=1) + cls.rastt = grass.tempname(10) + cls.runModule("r.mapcalc", expression=f"{cls.rastt}=1", quiet=True) + cls.tmp_rasts.append(cls.rastt) + cls.runModule("r.colors", _map=cls.rastt, color="grey", quiet=True) + cls.runModule("r.support", _map=cls.rastt, bandref="GRASS_RNDT", quiet=True) + # A raster without a band reference + cls.rast1 = grass.tempname(10) + cls.runModule("r.mapcalc", expression=f"{cls.rast1}=1", quiet=True) + cls.tmp_rasts.append(cls.rast1) + cls.runModule("r.colors", _map=cls.rast1, color="grey", quiet=True) + # A raster with a band reference + cls.rast2 = grass.tempname(10) + cls.runModule("r.mapcalc", expression=f"{cls.rast2}=1", quiet=True) + cls.tmp_rasts.append(cls.rast2) + cls.runModule("r.support", _map=cls.rast2, bandref="GRASS_RND1", quiet=True) + cls.rast3 = grass.tempname(10) + cls.runModule("r.mapcalc", expression=f"{cls.rast3}=1", quiet=True) + cls.tmp_rasts.append(cls.rast3) + cls.runModule("r.support", _map=cls.rast3, bandref="GRASS_RND2", quiet=True) + # An empty imagery group + cls.group1 = grass.tempname(10) + cls.runModule("i.group", group=cls.group1, _input=(cls.rast1,), quiet=True) + cls.tmp_groups.append(cls.group1) + cls.runModule( + "i.group", flags="r", group=cls.group1, _input=(cls.rast1,), quiet=True + ) + # An imagery group with raster lacking band reference + cls.group2 = grass.tempname(10) + cls.runModule("i.group", group=cls.group2, _input=(cls.rast1,), quiet=True) + cls.tmp_groups.append(cls.group2) + # A good imagery group + cls.group3 = grass.tempname(10) + cls.runModule( + "i.group", group=cls.group3, _input=(cls.rast2, cls.rast3), quiet=True + ) + cls.tmp_groups.append(cls.group3) + # A imagery group with different band count + cls.group4 = grass.tempname(10) + cls.runModule("i.group", group=cls.group4, _input=(cls.rast3), quiet=True) + cls.tmp_groups.append(cls.group4) + cls.group5 = grass.tempname(10) + cls.runModule( + "i.group", + group=cls.group5, + _input=(cls.rast2, cls.rast3, cls.rastt), + quiet=True, + ) + cls.tmp_groups.append(cls.group5) + # Generate a signature file + cls.sig1 = grass.tempname(10) + isvm = SimpleModule( + "i.svm.train", + group=cls.group3, + _input=cls.rastt, + signaturefile=cls.sig1, + quiet=True, + ) + isvm.run() + + @classmethod + def tearDownClass(cls): + """Remove the temporary region and generated data""" + cls.del_temp_region() + for rast in cls.tmp_rasts: + cls.runModule("g.remove", flags="f", _type="raster", name=rast) + for group in cls.tmp_groups: + cls.runModule("g.remove", flags="f", _type="group", name=group) + I_signatures_remove(I_SIGFILE_TYPE_LIBSVM, cls.sig1) + + @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") + def test_empty_group(self): + """Empty imagery group handling""" + rast = grass.tempname(10) + isvm = SimpleModule( + "i.svm.predict", + group=self.group1, + output=rast, + signaturefile=self.sig1, + quiet=True, + ) + self.tmp_rasts.append(rast) + self.assertModuleFail(isvm) + self.assertTrue(isvm.outputs.stderr) + self.assertIn(self.group1, isvm.outputs.stderr) + + @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") + def test_rast_no_bandref(self): + """One of imagery group rasters lacks band reference""" + rast = grass.tempname(10) + isvm = SimpleModule( + "i.svm.predict", + group=self.group2, + output=rast, + signaturefile=self.sig1, + quiet=True, + ) + self.tmp_rasts.append(rast) + self.assertModuleFail(isvm) + self.assertTrue(isvm.outputs.stderr) + self.assertIn(self.rast1, isvm.outputs.stderr) + + @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") + def test_bandref_mismatch1(self): + """There are more band references in the signature file than in the group""" + rast = grass.tempname(10) + isvm = SimpleModule( + "i.svm.predict", + group=self.group4, + output=rast, + signaturefile=self.sig1, + quiet=True, + ) + self.tmp_rasts.append(rast) + self.assertModuleFail(isvm) + self.assertTrue(isvm.outputs.stderr) + self.assertIn( + ( + "Imagery group does not contain a raster with a band reference 'GRASS_RND1'" + ), + isvm.outputs.stderr, + ) + + @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") + def test_bandref_mismatch1(self): + """There are more band references in the group than in the signature file""" + rast = grass.tempname(10) + isvm = SimpleModule( + "i.svm.predict", + group=self.group5, + output=rast, + signaturefile=self.sig1, + quiet=True, + ) + self.tmp_rasts.append(rast) + self.assertModuleFail(isvm) + self.assertTrue(isvm.outputs.stderr) + self.assertTrue( + "Signature band count: 2, imagery group band count: 3" + in isvm.outputs.stderr + ) + + @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") + def test_prediction(self): + """A successful run""" + rast = grass.tempname(10) + isvm = SimpleModule( + "i.svm.predict", + group=self.group3, + output=rast, + signaturefile=self.sig1, + quiet=True, + ) + self.tmp_rasts.append(rast) + self.assertModule(isvm) + self.assertRasterExists(rast) + + +if __name__ == "__main__": + test() diff --git a/imagery/i.svm.train/fill.c b/imagery/i.svm.train/fill.c index 1c351c53873..cb75401579d 100644 --- a/imagery/i.svm.train/fill.c +++ b/imagery/i.svm.train/fill.c @@ -86,7 +86,8 @@ void fill_problem(const char *name_labels, const char *mapset_labels, svm_node)); } problem->x[label_num][value_num].index = band; - problem->x[label_num][value_num].value = buf_bands[band][col]; + problem->x[label_num][value_num].value = + buf_bands[band][col] / 255; value_num++; } /* If label has no data */ diff --git a/imagery/i.svm.train/i.svm.train.html b/imagery/i.svm.train/i.svm.train.html index 527286e66c4..d28e550cabf 100644 --- a/imagery/i.svm.train/i.svm.train.html +++ b/imagery/i.svm.train/i.svm.train.html @@ -13,9 +13,9 @@

NOTES

Practical Guide to Support Vector Classification by Chih-Wei Hsu, Chih-Chung Chang, and Chih-Jen Lin.

-

The module requires all training data (feature value) rasters to -have band references set. Use r.support -to set band references if you get an error of missing band reference.

+

It is strongly suggested to have semantic labels set for each raster +map in the training data (feature value) imagery group. +Use r.support to set semantic labels.

PERFORMANCE

@@ -33,25 +33,9 @@

EXAMPLE

i.svm.predict for the second part.

Train a SVM to identify land use classes according to the 1996 land -use map landuse_96_28m and then classify a LANDSAT scene from +use map landuse96_28m and then classify a LANDSAT scene from October of 2002. Example requires the nc_spm_08 location.

-## Prepare imagery for classification
-# Skip this step if your rasters already have band references defined
-# Define band references for all LANDSAT bands in mapset PERMANENT
-g.mapset mapset=PERMANENT
-r.support map=lsat7_2002_10 bandref=TM7_1
-r.support map=lsat7_2002_20 bandref=TM7_2
-r.support map=lsat7_2002_30 bandref=TM7_3
-r.support map=lsat7_2002_40 bandref=TM7_4
-r.support map=lsat7_2002_50 bandref=TM7_5
-r.support map=lsat7_2002_61 bandref=TM7_61
-r.support map=lsat7_2002_62 bandref=TM7_62
-r.support map=lsat7_2002_70 bandref=TM7_7
-r.support map=lsat7_2002_80 bandref=TM7_8
-g.mapset mapset=user1  # replace user1 with your mapset name
-
-## Real work starts here
 # Align computation region to the scene
 g.region raster=lsat7_2002_10 -p
 
@@ -64,11 +48,11 @@ 

EXAMPLE

v.to.rast input=training output=training use=cat label_column=label # If you are just playing around and do not care about the accuracy of outcome, # just use one of existing maps instead e.g. -# r.random input=landuse96_28m npoints=5000 raster=training +# r.random input=landuse96_28m npoints=10000 raster=training # Train the SVM i.svm.train group=lsat7_2002 subgroup=lsat7_2002\ - input=training signaturefile=landuse_96_rnd_points + input=training signaturefile=landuse96_rnd_points # Go to i.svm.predict for the next step.
@@ -77,7 +61,7 @@

SEE ALSO

Predict values: i.svm.predict
-Set band references: r.support
+Set semantic labels: r.support
Other classification modules: i.maxlik, i.smap

diff --git a/imagery/i.svm.train/testsuite/test_i_svm_train.py b/imagery/i.svm.train/testsuite/test_i_svm_train.py index 3086013b332..68434747dd5 100644 --- a/imagery/i.svm.train/testsuite/test_i_svm_train.py +++ b/imagery/i.svm.train/testsuite/test_i_svm_train.py @@ -54,11 +54,15 @@ def setUpClass(cls): cls.rast2 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast2}=1", quiet=True) cls.tmp_rasts.append(cls.rast2) - cls.runModule("r.support", _map=cls.rast2, bandref="GRASS_RND", quiet=True) + cls.runModule("r.support", _map=cls.rast2, bandref="GRASS_RND1", quiet=True) cls.rast3 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast3}=1", quiet=True) cls.tmp_rasts.append(cls.rast3) - cls.runModule("r.support", _map=cls.rast3, bandref="GRASS_RND", quiet=True) + cls.runModule("r.support", _map=cls.rast3, bandref="GRASS_RND2", quiet=True) + cls.rast4 = grass.tempname(10) + cls.runModule("r.mapcalc", expression=f"{cls.rast4}=1", quiet=True) + cls.tmp_rasts.append(cls.rast4) + cls.runModule("r.support", _map=cls.rast4, bandref="GRASS_RND3", quiet=True) # An empty imagery group cls.group1 = grass.tempname(10) cls.runModule("i.group", group=cls.group1, _input=(cls.rast1,), quiet=True) @@ -183,6 +187,39 @@ def test_creation_of_misc_files(self): misc_file = utils.decode(cpath.value) self.assertTrue(os.path.isfile(misc_file)) + @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + def test_dont_fail_if_misc_files_missing(self): + """Colour file is missing but it should not cause a failure""" + sigfile = grass.tempname(10) + csigdir = ctypes.create_string_buffer(GNAME_MAX) + I_get_signatures_dir(csigdir, I_SIGFILE_TYPE_LIBSVM) + sigdir = utils.decode(csigdir.value) + isvm = SimpleModule( + "i.svm.train", + group=self.group3, + _input=self.rast4, + signaturefile=sigfile, + quiet=True, + ) + self.assertModule(isvm) + self.tmp_sigs.append(sigfile) + cpath = ctypes.create_string_buffer(GPATH_MAX) + G_file_name_misc(cpath, sigdir, "version", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "sig", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "cats", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "colr", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertFalse(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "history", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + if __name__ == "__main__": test() From 138f90c2638119fc48c04a7bbbf357ba2ff0ac29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 11 Feb 2022 14:12:01 +0200 Subject: [PATCH 020/123] i.svm: move from bandrefs to semantic labels --- imagery/i.svm.predict/main.c | 38 +++++++++---------- .../testsuite/test_i_svm_predict.py | 18 ++++----- imagery/i.svm.train/main.c | 20 +++++----- .../i.svm.train/testsuite/test_i_svm_train.py | 10 ++--- .../test_imagery_signature_management.py | 22 ++++++----- 5 files changed, 56 insertions(+), 52 deletions(-) diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c index c3000a87070..0c9eab295e7 100644 --- a/imagery/i.svm.predict/main.c +++ b/imagery/i.svm.predict/main.c @@ -51,9 +51,9 @@ int main(int argc, char *argv[]) struct Ref group_ref; char **names_ordered, **mapsets_ordered; - const char **bandrefs_group, **bandrefs_svm; - char bandref[GNAME_MAX]; - int bandref_count = 0, bandref_match_count = 0; + const char **semantic_labels_group, **semantic_labels_svm; + char semantic_label[GNAME_MAX]; + int semantic_label_count = 0, semantic_label_match_count = 0; struct svm_model *model; @@ -162,13 +162,13 @@ int main(int argc, char *argv[]) G_fatal_error(_("Group <%s@%s> contains no raster maps."), name_group, mapset_group); } - bandrefs_group = G_malloc(group_ref.nfiles * sizeof(char *)); + semantic_labels_group = G_malloc(group_ref.nfiles * sizeof(char *)); for (int n = 0; n < group_ref.nfiles; n++) { - bandrefs_group[n] = - Rast_read_bandref(group_ref.file[n].name, - group_ref.file[n].mapset); - if (!bandrefs_group[n]) - G_fatal_error(_("Raster map <%s@%s> lacks band reference"), + semantic_labels_group[n] = + Rast_read_semantic_label(group_ref.file[n].name, + group_ref.file[n].mapset); + if (!semantic_labels_group[n]) + G_fatal_error(_("Raster map <%s@%s> lacks semantic label"), group_ref.file[n].name, group_ref.file[n].mapset); } @@ -188,19 +188,19 @@ int main(int argc, char *argv[]) /* Reorder group items to match order from the signature file */ misc_file = - G_fopen_old_misc(sigfile_dir, "bandref", name_sigfile, + G_fopen_old_misc(sigfile_dir, "semantic_label", name_sigfile, mapset_sigfile); if (!misc_file) G_fatal_error(_("Unable to read signature file '%s'."), name_sigfile); names_ordered = G_malloc(group_ref.nfiles * sizeof(char *)); mapsets_ordered = G_malloc(group_ref.nfiles * sizeof(char *)); - while (fscanf(misc_file, "%" XSTR(GNAME_MAX) "s", bandref) == 1) { - bandref_count++; + while (fscanf(misc_file, "%" XSTR(GNAME_MAX) "s", semantic_label) == 1) { + semantic_label_count++; bool found = false; for (int n = 0; n < group_ref.nfiles; n++) { - if (bandref && strcmp(bandref, bandrefs_group[n]) == 0) { - bandref_match_count++; + if (semantic_label && strcmp(semantic_label, semantic_labels_group[n]) == 0) { + semantic_label_match_count++; found = true; names_ordered[n] = group_ref.file[n].name; mapsets_ordered[n] = group_ref.file[n].mapset; @@ -208,15 +208,15 @@ int main(int argc, char *argv[]) } } if (!found) - G_fatal_error(_("Imagery group does not contain a raster with a band reference '%s'"), - bandref); + G_fatal_error(_("Imagery group does not contain a raster with a semantic label '%s'"), + semantic_label); } fclose(misc_file); - if (bandref_match_count != bandref_count || - bandref_match_count != group_ref.nfiles) { + if (semantic_label_match_count != semantic_label_count || + semantic_label_match_count != group_ref.nfiles) { G_fatal_error(_("Unable to match all signature file bands to imagery group bands. " "Signature band count: %d, imagery group band count: %d, band match count: %d."), - bandref_count, group_ref.nfiles, bandref_match_count); + semantic_label_count, group_ref.nfiles, semantic_label_match_count); } /* Pass libsvm messages through GRASS */ diff --git a/imagery/i.svm.predict/testsuite/test_i_svm_predict.py b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py index 32f0913ea4c..6afa95d7926 100644 --- a/imagery/i.svm.predict/testsuite/test_i_svm_predict.py +++ b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py @@ -48,7 +48,7 @@ def setUpClass(cls): cls.runModule("r.mapcalc", expression=f"{cls.rastt}=1", quiet=True) cls.tmp_rasts.append(cls.rastt) cls.runModule("r.colors", _map=cls.rastt, color="grey", quiet=True) - cls.runModule("r.support", _map=cls.rastt, bandref="GRASS_RNDT", quiet=True) + cls.runModule("r.support", _map=cls.rastt, semantic_label="GRASS_RNDT", quiet=True) # A raster without a band reference cls.rast1 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast1}=1", quiet=True) @@ -58,11 +58,11 @@ def setUpClass(cls): cls.rast2 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast2}=1", quiet=True) cls.tmp_rasts.append(cls.rast2) - cls.runModule("r.support", _map=cls.rast2, bandref="GRASS_RND1", quiet=True) + cls.runModule("r.support", _map=cls.rast2, semantic_label="GRASS_RND1", quiet=True) cls.rast3 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast3}=1", quiet=True) cls.tmp_rasts.append(cls.rast3) - cls.runModule("r.support", _map=cls.rast3, bandref="GRASS_RND2", quiet=True) + cls.runModule("r.support", _map=cls.rast3, semantic_label="GRASS_RND2", quiet=True) # An empty imagery group cls.group1 = grass.tempname(10) cls.runModule("i.group", group=cls.group1, _input=(cls.rast1,), quiet=True) @@ -130,8 +130,8 @@ def test_empty_group(self): self.assertIn(self.group1, isvm.outputs.stderr) @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") - def test_rast_no_bandref(self): - """One of imagery group rasters lacks band reference""" + def test_rast_no_semantic_label(self): + """One of imagery group rasters lacks semantic label""" rast = grass.tempname(10) isvm = SimpleModule( "i.svm.predict", @@ -146,8 +146,8 @@ def test_rast_no_bandref(self): self.assertIn(self.rast1, isvm.outputs.stderr) @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") - def test_bandref_mismatch1(self): - """There are more band references in the signature file than in the group""" + def test_semantic_label_mismatch1(self): + """There are more semantic labels in the signature file than in the group""" rast = grass.tempname(10) isvm = SimpleModule( "i.svm.predict", @@ -167,8 +167,8 @@ def test_bandref_mismatch1(self): ) @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") - def test_bandref_mismatch1(self): - """There are more band references in the group than in the signature file""" + def test_semantic_label_mismatch1(self): + """There are more semantic labels in the group than in the signature file""" rast = grass.tempname(10) isvm = SimpleModule( "i.svm.predict", diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index 96de984a754..5a93c8b6375 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) char in_path[GPATH_MAX], out_path[GPATH_MAX]; struct Ref group_ref; - const char **bandrefs; + const char **semantic_labels; struct svm_parameter parameters; const char *parameters_error; @@ -354,13 +354,13 @@ int main(int argc, char *argv[]) G_fatal_error(_("Group <%s@%s> contains no raster maps."), name_group, mapset_group); } - bandrefs = G_malloc(group_ref.nfiles * sizeof(char *)); + semantic_labels = G_malloc(group_ref.nfiles * sizeof(char *)); for (int n = 0; n < group_ref.nfiles; n++) { - bandrefs[n] = - Rast_read_bandref(group_ref.file[n].name, - group_ref.file[n].mapset); - if (!bandrefs[n]) - G_fatal_error(_("Raster map <%s@%s> lacks band reference"), + semantic_labels[n] = + Rast_read_semantic_label(group_ref.file[n].name, + group_ref.file[n].mapset); + if (!semantic_labels[n]) + G_fatal_error(_("Raster map <%s@%s> lacks semantic label"), group_ref.file[n].name, group_ref.file[n].mapset); } @@ -407,15 +407,15 @@ int main(int argc, char *argv[]) } svm_free_and_destroy_model(&model); /* Write out band reference info */ - misc_file = G_fopen_new_misc(sigfile_dir, "bandref", name_sigfile); + misc_file = G_fopen_new_misc(sigfile_dir, "semantic_label", name_sigfile); if (!misc_file) G_fatal_error(_("Unable to write trained model to file '%s'."), name_sigfile); for (int n = 0; n < group_ref.nfiles; n++) { - fprintf(misc_file, "%s\n", bandrefs[n]); + fprintf(misc_file, "%s\n", semantic_labels[n]); } fclose(misc_file); - G_free(bandrefs); + G_free(semantic_labels); /* Copy CATs file. Will be used for prediction result maps */ G_verbose_message("Copying category information"); diff --git a/imagery/i.svm.train/testsuite/test_i_svm_train.py b/imagery/i.svm.train/testsuite/test_i_svm_train.py index 68434747dd5..8eff0bdced7 100644 --- a/imagery/i.svm.train/testsuite/test_i_svm_train.py +++ b/imagery/i.svm.train/testsuite/test_i_svm_train.py @@ -54,15 +54,15 @@ def setUpClass(cls): cls.rast2 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast2}=1", quiet=True) cls.tmp_rasts.append(cls.rast2) - cls.runModule("r.support", _map=cls.rast2, bandref="GRASS_RND1", quiet=True) + cls.runModule("r.support", _map=cls.rast2, semantic_label="GRASS_RND1", quiet=True) cls.rast3 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast3}=1", quiet=True) cls.tmp_rasts.append(cls.rast3) - cls.runModule("r.support", _map=cls.rast3, bandref="GRASS_RND2", quiet=True) + cls.runModule("r.support", _map=cls.rast3, semantic_label="GRASS_RND2", quiet=True) cls.rast4 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast4}=1", quiet=True) cls.tmp_rasts.append(cls.rast4) - cls.runModule("r.support", _map=cls.rast4, bandref="GRASS_RND3", quiet=True) + cls.runModule("r.support", _map=cls.rast4, semantic_label="GRASS_RND3", quiet=True) # An empty imagery group cls.group1 = grass.tempname(10) cls.runModule("i.group", group=cls.group1, _input=(cls.rast1,), quiet=True) @@ -108,8 +108,8 @@ def test_empty_group(self): self.assertIn(self.group1, isvm.outputs.stderr) @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") - def test_rast_no_bandref(self): - """One of imagery group rasters lacks band reference""" + def test_rast_no_semantic_label(self): + """One of imagery group rasters lacks semantic_label""" sigfile = grass.tempname(10) isvm = SimpleModule( "i.svm.train", diff --git a/lib/imagery/testsuite/test_imagery_signature_management.py b/lib/imagery/testsuite/test_imagery_signature_management.py index 52be476d867..2bf1486fc3d 100644 --- a/lib/imagery/testsuite/test_imagery_signature_management.py +++ b/lib/imagery/testsuite/test_imagery_signature_management.py @@ -44,7 +44,7 @@ H_DIRSEP = HOST_DIRSEP.decode("utf-8") -class GetSignaturesElementTestCase(TestCase): +class GetSignaturesDirTestCase(TestCase): def test_get_sig(self): cdir = ctypes.create_string_buffer(GNAME_MAX) I_get_signatures_dir(cdir, I_SIGFILE_TYPE_SIG) @@ -57,11 +57,11 @@ def test_get_sigset(self): def test_get_libsvm(self): elem = ctypes.create_string_buffer(GNAME_MAX) - I__get_signatures_element(elem, I_SIGFILE_TYPE_LIBSVM) + I_get_signatures_dir(elem, I_SIGFILE_TYPE_LIBSVM) self.assertEqual(utils.decode(elem.value), f"signatures{H_DIRSEP}libsvm") -class MakeSignaturesElementTestCase(TestCase): +class MakeSignaturesDirTestCase(TestCase): @classmethod def setUpClass(cls): cls.org_mapset = Mapset() @@ -99,12 +99,12 @@ def test_make_sigset(self): ) def test_make_libsvm(self): - I__make_signatures_element(I_SIGFILE_TYPE_LIBSVM) + I_make_signatures_dir(I_SIGFILE_TYPE_LIBSVM) self.assertTrue( os.path.isdir(os.path.join(self.tmp_mapset_path, "signatures", "libsvm")) ) # There should not be any side effects of calling function multiple times - I__make_signatures_element(I_SIGFILE_TYPE_SIGSET) + I_make_signatures_dir(I_SIGFILE_TYPE_SIGSET) self.assertTrue( os.path.isdir(os.path.join(self.tmp_mapset_path, "signatures", "libsvm")) ) @@ -302,9 +302,11 @@ def test_remove_existing_libsvm(self): open(sigfile_name2, "a").close() self.sigdirs.append(sig_dir2) sig_name3 = tempname(10) - sigfile_name3 = f"{self.mpath}/signatures/sig/{sig_name3}" + sig_dir3 = f"{self.mpath}/signatures/sig/{sig_name3}" + os.makedirs(sig_dir3) + sigfile_name3 = f"{sig_dir3}/sig" open(sigfile_name3, "a").close() - self.sigfiles.append(sigfile_name3) + self.sigdirs.append(sig_dir3) # Try to remove with wrong type ret = I_signatures_remove(I_SIGFILE_TYPE_SIG, sig_name2) self.assertEqual(ret, 1) @@ -335,9 +337,11 @@ def test_remove_existing_libsvm(self): def test_remove_nonexisting_libsvm(self): # Set up files and mark for clean-up sig_name1 = tempname(10) - sigfile_name1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + sig_dir1 = f"{self.mpath}/signatures/sigset/{sig_name1}" + os.makedirs(sig_dir1) + sigfile_name1 = f"{sig_dir1}/sig" open(sigfile_name1, "a").close() - self.sigfiles.append(sigfile_name1) + self.sigdirs.append(sig_dir1) sig_name2 = tempname(10) # Do not create sig_name2 matching file sig_name3 = tempname(10) From 99ed67b0aefdb7f29232364de0f77287001da043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 11 Feb 2022 14:13:37 +0200 Subject: [PATCH 021/123] i.svm: add libsvm detection to configure --- configure | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 278bb88bd96..3cb1b0bf240 100755 --- a/configure +++ b/configure @@ -652,6 +652,9 @@ CAIROLIB CAIROINC CAIRO_HAS_XRENDER_SURFACE CAIRO_HAS_XRENDER +USE_LIBSVM +LIBSVM_LIB +LIBSVM_INC LAPACKINC LAPACKLIB BLASINC @@ -836,6 +839,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -874,6 +878,7 @@ with_odbc with_fftw with_blas with_lapack +with_libsvm with_cairo with_freetype with_nls @@ -922,6 +927,8 @@ with_blas_includes with_blas_libs with_lapack_includes with_lapack_libs +with_libsvm_includes +with_libsvm_libs with_cairo_includes with_cairo_libs with_cairo_ldflags @@ -996,6 +1003,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' @@ -1248,6 +1256,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1385,7 +1402,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1538,6 +1555,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1598,6 +1616,7 @@ Optional Packages: --with-fftw support FFTW functionality (default: yes) --with-blas support BLAS functionality (default: no) --with-lapack support LAPACK functionality (default: no) + --with-libsvm support libsvm functionality (default: no) --with-cairo support Cairo functionality (default: yes) --with-freetype support FreeType functionality (default: yes) --with-nls support NLS functionality (default: no) @@ -1680,6 +1699,9 @@ Optional Packages: --with-lapack-includes=DIRS LAPACK include files are in DIRS --with-lapack-libs=DIRS LAPACK library files are in DIRS + --with-libsvm-includes=DIRS + libsvm include files are in DIRS + --with-libsvm-libs=DIRS libsvm library files are in DIRS --with-cairo-includes=DIRS cairo include files are in DIRS --with-cairo-libs=DIRS cairo library files are in DIRS @@ -4323,6 +4345,16 @@ fi +# Check whether --with-libsvm was given. +if test "${with_libsvm+set}" = set; then : + withval=$with_libsvm; +else + with_libsvm=no +fi + + + + # Check whether --with-cairo was given. if test "${with_cairo+set}" = set; then : withval=$with_cairo; @@ -4748,6 +4780,23 @@ fi +# Check whether --with-libsvm-includes was given. +if test "${with_libsvm_includes+set}" = set; then : + withval=$with_libsvm_includes; +fi + + + + +# Check whether --with-libsvm-libs was given. +if test "${with_libsvm_libs+set}" = set; then : + withval=$with_libsvm_libs; +fi + + + + + # Check whether --with-cairo-includes was given. if test "${with_cairo_includes+set}" = set; then : withval=$with_cairo_includes; @@ -13626,6 +13675,150 @@ fi # $USE_BLAS # Done checking LAPACK +# libsvm option +LIBSVM_INC= +LIBSVM_LIB= +USE_LIBSVM= + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use libsvm" >&5 +$as_echo_n "checking whether to use libsvm... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_libsvm\"" >&5 +$as_echo "\"$with_libsvm\"" >&6; } +case "$with_libsvm" in + "no") USE_LIBSVM= ;; + "yes") USE_LIBSVM="1" ;; + *) as_fn_error $? "*** You must answer yes or no." "$LINENO" 5 ;; +esac + + + +if test -n "$USE_LIBSVM"; then + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of libsvm includes" >&5 +$as_echo_n "checking for location of libsvm includes... " >&6; } +case "$with_libsvm_includes" in +y | ye | yes | n | no) + as_fn_error $? "*** You must supply a directory to --with-libsvm-includes." "$LINENO" 5 + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_libsvm_includes" >&5 +$as_echo "$with_libsvm_includes" >&6; } + +if test -n "$with_libsvm_includes" ; then + for dir in $with_libsvm_includes; do + if test -d "$dir"; then + LIBSVM_INC="$LIBSVM_INC -I$dir" + else + as_fn_error $? "*** libsvm includes directory $dir does not exist." "$LINENO" 5 + fi + done +fi + + +ac_save_cppflags="$CPPFLAGS" +CPPFLAGS="$LIBSVM_INC $CPPFLAGS" +for ac_header in libsvm/svm.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "libsvm/svm.h" "ac_cv_header_libsvm_svm_h" "$ac_includes_default" +if test "x$ac_cv_header_libsvm_svm_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSVM_SVM_H 1 +_ACEOF + +else + + as_fn_error $? "*** Unable to locate libsvm includes." "$LINENO" 5 + +fi + +done + +CPPFLAGS=$ac_save_cppflags + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of libsvm library" >&5 +$as_echo_n "checking for location of libsvm library... " >&6; } +case "$with_libsvm_libs" in +y | ye | yes | n | no) + as_fn_error $? "*** You must supply a directory to --with-libsvm-libs." "$LINENO" 5 + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_libsvm_libs" >&5 +$as_echo "$with_libsvm_libs" >&6; } + +if test -n "$with_libsvm_libs"; then + for dir in $with_libsvm_libs; do + if test -d "$dir"; then + LIBSVM_LIB="$LIBSVM_LIB -L$dir" + else + as_fn_error $? "*** libsvm library directory $dir does not exist." "$LINENO" 5 + fi + done +fi + + +ac_save_ldflags="$LDFLAGS" +LDFLAGS="$LIBSVM_LIB $LDFLAGS" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for svm_load_model in -lsvm" >&5 +$as_echo_n "checking for svm_load_model in -lsvm... " >&6; } + +ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char svm_load_model (); +int +main () +{ +return svm_load_model (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svm_svm_load_model=yes +else + ac_cv_lib_svm_svm_load_model=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svm_svm_load_model" >&5 +$as_echo "$ac_cv_lib_svm_svm_load_model" >&6; } +if test "x$ac_cv_lib_svm_svm_load_model" = xyes; then : + LIBSVM_LIB="$LIBSVM_LIB -lsvm " +else + +LDFLAGS=${ac_save_ldflags} + + as_fn_error $? "*** Unable to locate libsvm library." "$LINENO" 5 + + +fi + + + +LDFLAGS=${ac_save_ldflags} + + $as_echo "#define HAVE_LIBSVM 1" >>confdefs.h + +fi + + + + +# Done with libsvm + # Enable Cairo display driver option @@ -16739,6 +16932,8 @@ echo " Large File support (LFS): `if test -n "${USE_LARGEFILES}" ; then echo echo " libLAS support: `if test -n "${USE_LIBLAS}" ; then echo yes ; else echo no ; fi`" +echo " Libsvm support: `if test -n "${USE_LIBSVM}" ; then echo yes ; else echo no ; fi`" + echo " MySQL support: `if test -n "${USE_MYSQL}" ; then echo yes ; else echo no ; fi`" echo " NetCDF support: `if test -n "${USE_NETCDF}" ; then echo yes ; else echo no ; fi`" From 6c087f69775c800fcf6610a4ca099b9806a522da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 11 Feb 2022 14:28:31 +0200 Subject: [PATCH 022/123] i.svm: use raster names if semantic labels are missing (+ formatting fix) --- imagery/i.svm.predict/main.c | 10 ++++++---- .../i.svm.predict/testsuite/test_i_svm_predict.py | 12 +++++++++--- imagery/i.svm.train/main.c | 4 ++-- imagery/i.svm.train/testsuite/test_i_svm_train.py | 12 +++++++++--- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c index 0c9eab295e7..a88fc8ca9bc 100644 --- a/imagery/i.svm.predict/main.c +++ b/imagery/i.svm.predict/main.c @@ -165,8 +165,8 @@ int main(int argc, char *argv[]) semantic_labels_group = G_malloc(group_ref.nfiles * sizeof(char *)); for (int n = 0; n < group_ref.nfiles; n++) { semantic_labels_group[n] = - Rast_read_semantic_label(group_ref.file[n].name, - group_ref.file[n].mapset); + Rast_read_semantic_label_or_name(group_ref.file[n].name, + group_ref.file[n].mapset); if (!semantic_labels_group[n]) G_fatal_error(_("Raster map <%s@%s> lacks semantic label"), group_ref.file[n].name, group_ref.file[n].mapset); @@ -199,7 +199,8 @@ int main(int argc, char *argv[]) bool found = false; for (int n = 0; n < group_ref.nfiles; n++) { - if (semantic_label && strcmp(semantic_label, semantic_labels_group[n]) == 0) { + if (semantic_label && + strcmp(semantic_label, semantic_labels_group[n]) == 0) { semantic_label_match_count++; found = true; names_ordered[n] = group_ref.file[n].name; @@ -216,7 +217,8 @@ int main(int argc, char *argv[]) semantic_label_match_count != group_ref.nfiles) { G_fatal_error(_("Unable to match all signature file bands to imagery group bands. " "Signature band count: %d, imagery group band count: %d, band match count: %d."), - semantic_label_count, group_ref.nfiles, semantic_label_match_count); + semantic_label_count, group_ref.nfiles, + semantic_label_match_count); } /* Pass libsvm messages through GRASS */ diff --git a/imagery/i.svm.predict/testsuite/test_i_svm_predict.py b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py index 6afa95d7926..88938bcec90 100644 --- a/imagery/i.svm.predict/testsuite/test_i_svm_predict.py +++ b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py @@ -48,7 +48,9 @@ def setUpClass(cls): cls.runModule("r.mapcalc", expression=f"{cls.rastt}=1", quiet=True) cls.tmp_rasts.append(cls.rastt) cls.runModule("r.colors", _map=cls.rastt, color="grey", quiet=True) - cls.runModule("r.support", _map=cls.rastt, semantic_label="GRASS_RNDT", quiet=True) + cls.runModule( + "r.support", _map=cls.rastt, semantic_label="GRASS_RNDT", quiet=True + ) # A raster without a band reference cls.rast1 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast1}=1", quiet=True) @@ -58,11 +60,15 @@ def setUpClass(cls): cls.rast2 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast2}=1", quiet=True) cls.tmp_rasts.append(cls.rast2) - cls.runModule("r.support", _map=cls.rast2, semantic_label="GRASS_RND1", quiet=True) + cls.runModule( + "r.support", _map=cls.rast2, semantic_label="GRASS_RND1", quiet=True + ) cls.rast3 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast3}=1", quiet=True) cls.tmp_rasts.append(cls.rast3) - cls.runModule("r.support", _map=cls.rast3, semantic_label="GRASS_RND2", quiet=True) + cls.runModule( + "r.support", _map=cls.rast3, semantic_label="GRASS_RND2", quiet=True + ) # An empty imagery group cls.group1 = grass.tempname(10) cls.runModule("i.group", group=cls.group1, _input=(cls.rast1,), quiet=True) diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index 5a93c8b6375..80d4cb97f2a 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -357,8 +357,8 @@ int main(int argc, char *argv[]) semantic_labels = G_malloc(group_ref.nfiles * sizeof(char *)); for (int n = 0; n < group_ref.nfiles; n++) { semantic_labels[n] = - Rast_read_semantic_label(group_ref.file[n].name, - group_ref.file[n].mapset); + Rast_read_semantic_label_or_name(group_ref.file[n].name, + group_ref.file[n].mapset); if (!semantic_labels[n]) G_fatal_error(_("Raster map <%s@%s> lacks semantic label"), group_ref.file[n].name, group_ref.file[n].mapset); diff --git a/imagery/i.svm.train/testsuite/test_i_svm_train.py b/imagery/i.svm.train/testsuite/test_i_svm_train.py index 8eff0bdced7..90c230ae334 100644 --- a/imagery/i.svm.train/testsuite/test_i_svm_train.py +++ b/imagery/i.svm.train/testsuite/test_i_svm_train.py @@ -54,15 +54,21 @@ def setUpClass(cls): cls.rast2 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast2}=1", quiet=True) cls.tmp_rasts.append(cls.rast2) - cls.runModule("r.support", _map=cls.rast2, semantic_label="GRASS_RND1", quiet=True) + cls.runModule( + "r.support", _map=cls.rast2, semantic_label="GRASS_RND1", quiet=True + ) cls.rast3 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast3}=1", quiet=True) cls.tmp_rasts.append(cls.rast3) - cls.runModule("r.support", _map=cls.rast3, semantic_label="GRASS_RND2", quiet=True) + cls.runModule( + "r.support", _map=cls.rast3, semantic_label="GRASS_RND2", quiet=True + ) cls.rast4 = grass.tempname(10) cls.runModule("r.mapcalc", expression=f"{cls.rast4}=1", quiet=True) cls.tmp_rasts.append(cls.rast4) - cls.runModule("r.support", _map=cls.rast4, semantic_label="GRASS_RND3", quiet=True) + cls.runModule( + "r.support", _map=cls.rast4, semantic_label="GRASS_RND3", quiet=True + ) # An empty imagery group cls.group1 = grass.tempname(10) cls.runModule("i.group", group=cls.group1, _input=(cls.rast1,), quiet=True) From e9c5344bc7fe0c52eb58ef5ef90dc01d8bb9b5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 11 Feb 2022 15:37:05 +0200 Subject: [PATCH 023/123] i.svm: remove blank line left after merge --- lib/imagery/testsuite/test_imagery_signature_management.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/imagery/testsuite/test_imagery_signature_management.py b/lib/imagery/testsuite/test_imagery_signature_management.py index 2bf1486fc3d..453b697d637 100644 --- a/lib/imagery/testsuite/test_imagery_signature_management.py +++ b/lib/imagery/testsuite/test_imagery_signature_management.py @@ -807,7 +807,6 @@ def test_no_sigs_at_all(self): self.assertEqual(ret, 0) I_free_signatures_list(ret, ctypes.byref(sig_list)) - def test_sig_in_different_mapset(self): # Should return 0 signatures from a different mapset # Sig type From fbe894cfa2ed82cefb3afaf0f500e4735f3ad06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Sun, 13 Feb 2022 13:02:29 +0200 Subject: [PATCH 024/123] i.svm: add libsvm signatures to GUI as a sigfile choice --- gui/wxpython/gui_core/gselect.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index e1e4283a0ab..b3496cd660d 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -2821,6 +2821,7 @@ def _append_mapset_signatures(self, mapset, element, items): from grass.lib.imagery import ( I_SIGFILE_TYPE_SIG, I_SIGFILE_TYPE_SIGSET, + I_SIGFILE_TYPE_LIBSVM, I_signatures_list_by_type, I_free_signatures_list, ) @@ -2834,6 +2835,8 @@ def _append_mapset_signatures(self, mapset, element, items): sig_type = I_SIGFILE_TYPE_SIG elif element == "signatures/sigset": sig_type = I_SIGFILE_TYPE_SIGSET + elif element == "signatures/libsvm": + sig_type = I_SIGFILE_TYPE_LIBSVM else: return list_ptr = ctypes.POINTER(ctypes.c_char_p) From 8bd447f8a42877a7bc01036f5e9c4d2ef2734b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Sun, 13 Feb 2022 13:34:02 +0200 Subject: [PATCH 025/123] i.svm: rescale imagery group band values to improve prediction --- imagery/i.svm.predict/i.svm.predict.html | 3 ++ imagery/i.svm.predict/main.c | 28 ++++++++++-- imagery/i.svm.train/fill.c | 6 +-- imagery/i.svm.train/fill.h | 2 +- imagery/i.svm.train/i.svm.train.html | 4 ++ imagery/i.svm.train/main.c | 54 +++++++++++++++++++++--- 6 files changed, 84 insertions(+), 13 deletions(-) diff --git a/imagery/i.svm.predict/i.svm.predict.html b/imagery/i.svm.predict/i.svm.predict.html index c8f3db53d75..83b012814e9 100644 --- a/imagery/i.svm.predict/i.svm.predict.html +++ b/imagery/i.svm.predict/i.svm.predict.html @@ -5,6 +5,9 @@

DESCRIPTION

generated with i.svm.train.

+

Internally the module performs input value rescaling of each of imagery +group rasters by minimum and maximum range determined during training.

+

NOTES

i.svm.train internally is using the libsvm. For introduction diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c index a88fc8ca9bc..95a1816292c 100644 --- a/imagery/i.svm.predict/main.c +++ b/imagery/i.svm.predict/main.c @@ -60,6 +60,8 @@ int main(int argc, char *argv[]) struct History history; FILE *misc_file; int sigfile_version; + double *rescale, r; + int rescale_count = 0; G_gisinit(argv[0]); @@ -165,8 +167,8 @@ int main(int argc, char *argv[]) semantic_labels_group = G_malloc(group_ref.nfiles * sizeof(char *)); for (int n = 0; n < group_ref.nfiles; n++) { semantic_labels_group[n] = - Rast_read_semantic_label_or_name(group_ref.file[n].name, - group_ref.file[n].mapset); + Rast_get_semantic_label_or_name(group_ref.file[n].name, + group_ref.file[n].mapset); if (!semantic_labels_group[n]) G_fatal_error(_("Raster map <%s@%s> lacks semantic label"), group_ref.file[n].name, group_ref.file[n].mapset); @@ -221,6 +223,23 @@ int main(int argc, char *argv[]) semantic_label_match_count); } + /* Read rescaling parameter */ + rescale = G_malloc(group_ref.nfiles * sizeof(double)); + misc_file = + G_fopen_old_misc(sigfile_dir, "rescale", name_sigfile, + mapset_sigfile); + while (fscanf(misc_file, "%lf", &r) == 1) { + if (rescale_count == group_ref.nfiles) { + G_fatal_error(_("Invalid signature file")); + } + rescale[rescale_count] = r; + rescale_count++; + } + fclose(misc_file); + if (rescale_count < group_ref.nfiles) { + G_fatal_error(_("Invalid signature file")); + } + /* Pass libsvm messages through GRASS */ svm_set_print_string_function(&print_func); @@ -280,7 +299,7 @@ int main(int argc, char *argv[]) if (Rast_is_d_null_value(&buf_bands[band][col])) continue; nodes[band].index = band; - nodes[band].value = buf_bands[band][col] / 255; + nodes[band].value = buf_bands[band][col] / rescale[band]; } /* All values where NULLs */ @@ -317,7 +336,7 @@ int main(int argc, char *argv[]) if (Rast_is_d_null_value(&buf_bands[band][col])) continue; nodes[band].index = band; - nodes[band].value = buf_bands[band][col] / 255; + nodes[band].value = buf_bands[band][col] / rescale[band]; } /* All values where NULLs */ @@ -344,6 +363,7 @@ int main(int argc, char *argv[]) G_free(buf_bands[band]); } G_free(nodes); + G_free(rescale); /* Try to give full history */ G_verbose_message("Writing out history"); diff --git a/imagery/i.svm.train/fill.c b/imagery/i.svm.train/fill.c index cb75401579d..0582548c62a 100644 --- a/imagery/i.svm.train/fill.c +++ b/imagery/i.svm.train/fill.c @@ -9,13 +9,14 @@ * */ #include +#include #include "fill.h" void fill_problem(const char *name_labels, const char *mapset_labels, struct Ref band_refs, const char *mapset_group, - struct svm_problem *problem) + double *rescale, struct svm_problem *problem) { int label_num, label_max; int value_num, value_max; @@ -51,7 +52,6 @@ void fill_problem(const char *name_labels, const char *mapset_labels, band_refs.file[band].mapset); } - for (row = 0; row < nrows; row++) { G_percent(row, nrows, 10); Rast_get_d_row(fd_labels, buf_labels, row); @@ -87,7 +87,7 @@ void fill_problem(const char *name_labels, const char *mapset_labels, } problem->x[label_num][value_num].index = band; problem->x[label_num][value_num].value = - buf_bands[band][col] / 255; + buf_bands[band][col] / rescale[band]; value_num++; } /* If label has no data */ diff --git a/imagery/i.svm.train/fill.h b/imagery/i.svm.train/fill.h index 51298172a0c..0251cd6046f 100644 --- a/imagery/i.svm.train/fill.h +++ b/imagery/i.svm.train/fill.h @@ -19,6 +19,6 @@ #define SIZE_INCREMENT 64; void fill_problem(const char *, const char *, struct Ref, const char *, - struct svm_problem *); + double *, struct svm_problem *); #endif // FILL_H diff --git a/imagery/i.svm.train/i.svm.train.html b/imagery/i.svm.train/i.svm.train.html index d28e550cabf..f35f8360649 100644 --- a/imagery/i.svm.train/i.svm.train.html +++ b/imagery/i.svm.train/i.svm.train.html @@ -5,6 +5,10 @@

DESCRIPTION

i.svm.predict.

+

Internally the module performs input value rescaling of each of imagery +group rasters by its minimum and maximum value. Rescaling parameters are +written into the signature file for use during prediction.

+

NOTES

i.svm.train internally is using the libsvm. For introduction diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index 80d4cb97f2a..02a0664f01b 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -66,7 +66,12 @@ int main(int argc, char *argv[]) struct Categories cats; struct History history; FILE *misc_file; - int i; + int i, ret; + double *rescale; + struct Range crange; + struct FPRange fprange; + int cmin, cmax; + double dmin, dmax; G_gisinit(argv[0]); @@ -355,13 +360,40 @@ int main(int argc, char *argv[]) name_group, mapset_group); } semantic_labels = G_malloc(group_ref.nfiles * sizeof(char *)); + rescale = G_malloc(group_ref.nfiles * sizeof(double)); for (int n = 0; n < group_ref.nfiles; n++) { semantic_labels[n] = - Rast_read_semantic_label_or_name(group_ref.file[n].name, - group_ref.file[n].mapset); + Rast_get_semantic_label_or_name(group_ref.file[n].name, + group_ref.file[n].mapset); if (!semantic_labels[n]) G_fatal_error(_("Raster map <%s@%s> lacks semantic label"), group_ref.file[n].name, group_ref.file[n].mapset); + /* Use raster range for value rescaling */ + ret = Rast_read_range(group_ref.file[n].name, + group_ref.file[n].mapset, &crange); + if (ret == 1) { + Rast_get_range_min_max(&crange, &cmin, &cmax); + rescale[n] = (double)(cmax - cmin); + } + else if (ret == 3) { + ret = Rast_read_fp_range(group_ref.file[n].name, + group_ref.file[n].mapset, &fprange); + if (ret != 1) { + G_fatal_error(_("Unable to get value range for raster map <%s@%s>"), + group_ref.file[n].name, + group_ref.file[n].mapset); + } + Rast_get_fp_range_min_max(&fprange, &dmin, &dmax); + rescale[n] = dmax - dmin; + } + else { + G_fatal_error(_("Unable to get value range for raster map <%s@%s>"), + group_ref.file[n].name, group_ref.file[n].mapset); + } + if (rescale[n] < GRASS_EPSILON) { + G_fatal_error(_("Invalid value range for raster map <%s@%s>"), + group_ref.file[n].name, group_ref.file[n].mapset); + } } /* Pass libsvm messages through GRASS */ @@ -370,7 +402,7 @@ int main(int argc, char *argv[]) /* Fill svm_problem struct with training data */ G_message(_("Reading training data")); fill_problem(name_labels, mapset_labels, group_ref, mapset_group, - &problem); + rescale, &problem); /* svm_check_parameter needs filled svm_problem struct thus checking only now */ G_verbose_message("Checking SVM parametrization"); @@ -406,7 +438,7 @@ int main(int argc, char *argv[]) out_path, out_status); } svm_free_and_destroy_model(&model); - /* Write out band reference info */ + /* Write out semantic label info */ misc_file = G_fopen_new_misc(sigfile_dir, "semantic_label", name_sigfile); if (!misc_file) G_fatal_error(_("Unable to write trained model to file '%s'."), @@ -417,6 +449,18 @@ int main(int argc, char *argv[]) fclose(misc_file); G_free(semantic_labels); + /* Write out rescaling value as the same value has to be used for prediction */ + G_verbose_message("Writing out rescaling value"); + misc_file = G_fopen_new_misc(sigfile_dir, "rescale", name_sigfile); + if (!misc_file) + G_fatal_error(_("Unable to write trained model to file '%s'."), + name_sigfile); + for (int n = 0; n < group_ref.nfiles; n++) { + fprintf(misc_file, "%lf\n", rescale[n]); + } + fclose(misc_file); + G_free(rescale); + /* Copy CATs file. Will be used for prediction result maps */ G_verbose_message("Copying category information"); if (Rast_read_cats(name_labels, mapset_labels, &cats) == 0) { From 42631e537b07af55c1d6558853212db64ccaadcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 25 Feb 2022 13:32:43 +0200 Subject: [PATCH 026/123] i.svm: Add i.svm modules to GUI menu --- gui/wxpython/xml/toolboxes.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gui/wxpython/xml/toolboxes.xml b/gui/wxpython/xml/toolboxes.xml index 57653bab094..101bd7b402a 100644 --- a/gui/wxpython/xml/toolboxes.xml +++ b/gui/wxpython/xml/toolboxes.xml @@ -1544,6 +1544,13 @@ + + + + + + + From 0200b3ce45a11bf2b4ae89524bcee397d35a85e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 25 Feb 2022 15:28:48 +0200 Subject: [PATCH 027/123] i.svm: test tests to match new semantic label logic --- imagery/i.svm.predict/main.c | 3 -- .../testsuite/test_i_svm_predict.py | 52 +++++++------------ imagery/i.svm.train/main.c | 3 -- .../i.svm.train/testsuite/test_i_svm_train.py | 41 ++++++--------- 4 files changed, 35 insertions(+), 64 deletions(-) diff --git a/imagery/i.svm.predict/main.c b/imagery/i.svm.predict/main.c index 95a1816292c..55c747920c8 100644 --- a/imagery/i.svm.predict/main.c +++ b/imagery/i.svm.predict/main.c @@ -169,9 +169,6 @@ int main(int argc, char *argv[]) semantic_labels_group[n] = Rast_get_semantic_label_or_name(group_ref.file[n].name, group_ref.file[n].mapset); - if (!semantic_labels_group[n]) - G_fatal_error(_("Raster map <%s@%s> lacks semantic label"), - group_ref.file[n].name, group_ref.file[n].mapset); } I_get_signatures_dir(sigfile_dir, I_SIGFILE_TYPE_LIBSVM); diff --git a/imagery/i.svm.predict/testsuite/test_i_svm_predict.py b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py index 88938bcec90..9d0fe6b1007 100644 --- a/imagery/i.svm.predict/testsuite/test_i_svm_predict.py +++ b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py @@ -43,28 +43,36 @@ def setUpClass(cls): cls.mapset_name = Mapset().name # Small region for small testing rasters cls.use_temp_region() - cls.runModule("g.region", n=1, s=0, e=1, w=0, res=1) + cls.runModule("g.region", n=10, s=0, e=10, w=0, res=1) cls.rastt = grass.tempname(10) - cls.runModule("r.mapcalc", expression=f"{cls.rastt}=1", quiet=True) + cls.runModule( + "r.mapcalc", expression=f"{cls.rastt}=rand(0.0,1)", seed=1, quiet=True + ) cls.tmp_rasts.append(cls.rastt) cls.runModule("r.colors", _map=cls.rastt, color="grey", quiet=True) cls.runModule( "r.support", _map=cls.rastt, semantic_label="GRASS_RNDT", quiet=True ) - # A raster without a band reference + # A raster without a semantic label cls.rast1 = grass.tempname(10) - cls.runModule("r.mapcalc", expression=f"{cls.rast1}=1", quiet=True) + cls.runModule( + "r.mapcalc", expression=f"{cls.rast1}=rand(0.0,1)", seed=1, quiet=True + ) cls.tmp_rasts.append(cls.rast1) cls.runModule("r.colors", _map=cls.rast1, color="grey", quiet=True) - # A raster with a band reference + # A raster with a semantic label cls.rast2 = grass.tempname(10) - cls.runModule("r.mapcalc", expression=f"{cls.rast2}=1", quiet=True) + cls.runModule( + "r.mapcalc", expression=f"{cls.rast2}=rand(0.0,1)", seed=1, quiet=True + ) cls.tmp_rasts.append(cls.rast2) cls.runModule( "r.support", _map=cls.rast2, semantic_label="GRASS_RND1", quiet=True ) cls.rast3 = grass.tempname(10) - cls.runModule("r.mapcalc", expression=f"{cls.rast3}=1", quiet=True) + cls.runModule( + "r.mapcalc", expression=f"{cls.rast3}=rand(0.0,1)", seed=1, quiet=True + ) cls.tmp_rasts.append(cls.rast3) cls.runModule( "r.support", _map=cls.rast3, semantic_label="GRASS_RND2", quiet=True @@ -76,17 +84,13 @@ def setUpClass(cls): cls.runModule( "i.group", flags="r", group=cls.group1, _input=(cls.rast1,), quiet=True ) - # An imagery group with raster lacking band reference - cls.group2 = grass.tempname(10) - cls.runModule("i.group", group=cls.group2, _input=(cls.rast1,), quiet=True) - cls.tmp_groups.append(cls.group2) # A good imagery group cls.group3 = grass.tempname(10) cls.runModule( - "i.group", group=cls.group3, _input=(cls.rast2, cls.rast3), quiet=True + "i.group", group=cls.group3, _input=(cls.rast1, cls.rast3), quiet=True ) cls.tmp_groups.append(cls.group3) - # A imagery group with different band count + # A imagery group with different semantic label count cls.group4 = grass.tempname(10) cls.runModule("i.group", group=cls.group4, _input=(cls.rast3), quiet=True) cls.tmp_groups.append(cls.group4) @@ -94,7 +98,7 @@ def setUpClass(cls): cls.runModule( "i.group", group=cls.group5, - _input=(cls.rast2, cls.rast3, cls.rastt), + _input=(cls.rast1, cls.rast3, cls.rastt), quiet=True, ) cls.tmp_groups.append(cls.group5) @@ -117,7 +121,7 @@ def tearDownClass(cls): cls.runModule("g.remove", flags="f", _type="raster", name=rast) for group in cls.tmp_groups: cls.runModule("g.remove", flags="f", _type="group", name=group) - I_signatures_remove(I_SIGFILE_TYPE_LIBSVM, cls.sig1) + # I_signatures_remove(I_SIGFILE_TYPE_LIBSVM, cls.sig1) @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") def test_empty_group(self): @@ -135,22 +139,6 @@ def test_empty_group(self): self.assertTrue(isvm.outputs.stderr) self.assertIn(self.group1, isvm.outputs.stderr) - @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") - def test_rast_no_semantic_label(self): - """One of imagery group rasters lacks semantic label""" - rast = grass.tempname(10) - isvm = SimpleModule( - "i.svm.predict", - group=self.group2, - output=rast, - signaturefile=self.sig1, - quiet=True, - ) - self.tmp_rasts.append(rast) - self.assertModuleFail(isvm) - self.assertTrue(isvm.outputs.stderr) - self.assertIn(self.rast1, isvm.outputs.stderr) - @unittest.skipIf(shutil_which("i.svm.predict") is None, "i.svm.predict not found.") def test_semantic_label_mismatch1(self): """There are more semantic labels in the signature file than in the group""" @@ -167,7 +155,7 @@ def test_semantic_label_mismatch1(self): self.assertTrue(isvm.outputs.stderr) self.assertIn( ( - "Imagery group does not contain a raster with a band reference 'GRASS_RND1'" + "Imagery group does not contain a raster with a semantic label 'GRASS_RND1'" ), isvm.outputs.stderr, ) diff --git a/imagery/i.svm.train/main.c b/imagery/i.svm.train/main.c index 02a0664f01b..49fa28e10cf 100644 --- a/imagery/i.svm.train/main.c +++ b/imagery/i.svm.train/main.c @@ -365,9 +365,6 @@ int main(int argc, char *argv[]) semantic_labels[n] = Rast_get_semantic_label_or_name(group_ref.file[n].name, group_ref.file[n].mapset); - if (!semantic_labels[n]) - G_fatal_error(_("Raster map <%s@%s> lacks semantic label"), - group_ref.file[n].name, group_ref.file[n].mapset); /* Use raster range for value rescaling */ ret = Rast_read_range(group_ref.file[n].name, group_ref.file[n].mapset, &crange); diff --git a/imagery/i.svm.train/testsuite/test_i_svm_train.py b/imagery/i.svm.train/testsuite/test_i_svm_train.py index 90c230ae334..e3e7f65b19b 100644 --- a/imagery/i.svm.train/testsuite/test_i_svm_train.py +++ b/imagery/i.svm.train/testsuite/test_i_svm_train.py @@ -44,27 +44,35 @@ def setUpClass(cls): cls.mapset_name = Mapset().name # Small region for small testing rasters cls.use_temp_region() - cls.runModule("g.region", n=1, s=0, e=1, w=0, res=1) - # A raster without a band reference + cls.runModule("g.region", n=10, s=0, e=10, w=0, res=1) + # A raster without a semantic label cls.rast1 = grass.tempname(10) - cls.runModule("r.mapcalc", expression=f"{cls.rast1}=1", quiet=True) + cls.runModule( + "r.mapcalc", expression=f"{cls.rast1}=rand(0.0,1)", seed=1, quiet=True + ) cls.tmp_rasts.append(cls.rast1) cls.runModule("r.colors", _map=cls.rast1, color="grey", quiet=True) - # A raster with a band reference + # A raster with a semantic label cls.rast2 = grass.tempname(10) - cls.runModule("r.mapcalc", expression=f"{cls.rast2}=1", quiet=True) + cls.runModule( + "r.mapcalc", expression=f"{cls.rast2}=rand(0.0,1)", seed=1, quiet=True + ) cls.tmp_rasts.append(cls.rast2) cls.runModule( "r.support", _map=cls.rast2, semantic_label="GRASS_RND1", quiet=True ) cls.rast3 = grass.tempname(10) - cls.runModule("r.mapcalc", expression=f"{cls.rast3}=1", quiet=True) + cls.runModule( + "r.mapcalc", expression=f"{cls.rast3}=rand(0.0,1)", seed=1, quiet=True + ) cls.tmp_rasts.append(cls.rast3) cls.runModule( "r.support", _map=cls.rast3, semantic_label="GRASS_RND2", quiet=True ) cls.rast4 = grass.tempname(10) - cls.runModule("r.mapcalc", expression=f"{cls.rast4}=1", quiet=True) + cls.runModule( + "r.mapcalc", expression=f"{cls.rast4}=rand(0.0,1)", seed=1, quiet=True + ) cls.tmp_rasts.append(cls.rast4) cls.runModule( "r.support", _map=cls.rast4, semantic_label="GRASS_RND3", quiet=True @@ -76,10 +84,6 @@ def setUpClass(cls): cls.runModule( "i.group", flags="r", group=cls.group1, _input=(cls.rast1,), quiet=True ) - # An imagery group with raster lacking band reference - cls.group2 = grass.tempname(10) - cls.runModule("i.group", group=cls.group2, _input=(cls.rast1,), quiet=True) - cls.tmp_groups.append(cls.group2) # A good imagery group cls.group3 = grass.tempname(10) cls.runModule( @@ -113,21 +117,6 @@ def test_empty_group(self): self.assertTrue(isvm.outputs.stderr) self.assertIn(self.group1, isvm.outputs.stderr) - @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") - def test_rast_no_semantic_label(self): - """One of imagery group rasters lacks semantic_label""" - sigfile = grass.tempname(10) - isvm = SimpleModule( - "i.svm.train", - group=self.group2, - _input=self.rast1, - signaturefile=sigfile, - quiet=True, - ) - self.assertModuleFail(isvm) - self.assertTrue(isvm.outputs.stderr) - self.assertIn(self.rast1, isvm.outputs.stderr) - @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") def test_wrong_sigfile_mapset(self): """Attempt to use FQ signature file name with not current mapset""" From ab3ebfca815755f90cd8029bb183ef94a0d042eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 26 Aug 2022 17:55:26 +0300 Subject: [PATCH 028/123] v.random: do not transfer cat from area if attributes are coppied too Current code creates two cat entries for each point on the same level - one from area point is in and one matching new entry in the database. As entries in db have new cat values, old cat value points to a random or non-existing entry in the db thus causing a mess. Fixes #2475. --- vector/v.random/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/v.random/main.c b/vector/v.random/main.c index 5fe680e36b5..0912294f27a 100644 --- a/vector/v.random/main.c +++ b/vector/v.random/main.c @@ -672,7 +672,7 @@ int main(int argc, char *argv[]) cats_array[i].cat = cat; cats_array[i].val = cat_area; - + Vect_reset_cats(Cats); } sprintf(buf, "insert into %s (%s", Fi->table, Fi->key); From 9b31ab266680e9d8215b277ebf589947077c27a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Fri, 9 Sep 2022 12:21:23 +0300 Subject: [PATCH 029/123] i.svm.train: test value rescaling --- .../i.svm.train/testsuite/test_i_svm_train.py | 79 +++++++++++++++++-- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/imagery/i.svm.train/testsuite/test_i_svm_train.py b/imagery/i.svm.train/testsuite/test_i_svm_train.py index e3e7f65b19b..91b565f2b82 100644 --- a/imagery/i.svm.train/testsuite/test_i_svm_train.py +++ b/imagery/i.svm.train/testsuite/test_i_svm_train.py @@ -11,9 +11,9 @@ import os import unittest import ctypes +import shutil from grass.script import core as grass -from grass.script import shutil_which from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule @@ -36,7 +36,7 @@ class IOValidationTest(TestCase): """Test input validation and output generation with i.svm.train""" @classmethod - @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + @unittest.skipIf(shutil.which("i.svm.train") is None, "i.svm.train not found.") def setUpClass(cls): cls.tmp_rasts = [] cls.tmp_groups = [] @@ -77,6 +77,25 @@ def setUpClass(cls): cls.runModule( "r.support", _map=cls.rast4, semantic_label="GRASS_RND3", quiet=True ) + cls.rast5 = grass.tempname(10) + cls.runModule( + "r.mapcalc", expression=f"{cls.rast5}=rand(-1.0,1)", seed=1, quiet=True + ) + cls.tmp_rasts.append(cls.rast5) + cls.runModule( + "r.support", _map=cls.rast5, semantic_label="GRASS_RND4", quiet=True + ) + cls.rast6 = grass.tempname(10) + cls.runModule( + "r.mapcalc", + expression=f"{cls.rast6}=if(row() == 1 && col() == 1, 10, if(row() == 2 && col() == 2, -10, rand(-10.0,10)))", + seed=1, + quiet=True, + ) + cls.tmp_rasts.append(cls.rast6) + cls.runModule( + "r.support", _map=cls.rast6, semantic_label="GRASS_RND5", quiet=True + ) # An empty imagery group cls.group1 = grass.tempname(10) cls.runModule("i.group", group=cls.group1, _input=(cls.rast1,), quiet=True) @@ -90,6 +109,12 @@ def setUpClass(cls): "i.group", group=cls.group3, _input=(cls.rast2, cls.rast3), quiet=True ) cls.tmp_groups.append(cls.group3) + # Range test group + cls.group4 = grass.tempname(10) + cls.runModule( + "i.group", group=cls.group4, _input=(cls.rast5, cls.rast6), quiet=True + ) + cls.tmp_groups.append(cls.group4) @classmethod def tearDownClass(cls): @@ -102,7 +127,7 @@ def tearDownClass(cls): for sig in cls.tmp_sigs: I_signatures_remove(I_SIGFILE_TYPE_LIBSVM, sig) - @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + @unittest.skipIf(shutil.which("i.svm.train") is None, "i.svm.train not found.") def test_empty_group(self): """Empty imagery group handling""" sigfile = grass.tempname(10) @@ -117,7 +142,7 @@ def test_empty_group(self): self.assertTrue(isvm.outputs.stderr) self.assertIn(self.group1, isvm.outputs.stderr) - @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + @unittest.skipIf(shutil.which("i.svm.train") is None, "i.svm.train not found.") def test_wrong_sigfile_mapset(self): """Attempt to use FQ signature file name with not current mapset""" sigfile = grass.tempname(10) @@ -133,7 +158,7 @@ def test_wrong_sigfile_mapset(self): self.assertTrue(isvm.outputs.stderr) self.assertIn(mapset, isvm.outputs.stderr) - @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + @unittest.skipIf(shutil.which("i.svm.train") is None, "i.svm.train not found.") def test_wrong_svm_param(self): """Attempt to use invalid SVM parametres""" sigfile = grass.tempname(10) @@ -149,7 +174,7 @@ def test_wrong_svm_param(self): self.assertTrue(isvm.outputs.stderr) self.assertIn("eps", isvm.outputs.stderr) - @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + @unittest.skipIf(shutil.which("i.svm.train") is None, "i.svm.train not found.") def test_creation_of_misc_files(self): """Validate creation of category, history and colour files""" sigfile = grass.tempname(10) @@ -182,7 +207,7 @@ def test_creation_of_misc_files(self): misc_file = utils.decode(cpath.value) self.assertTrue(os.path.isfile(misc_file)) - @unittest.skipIf(shutil_which("i.svm.train") is None, "i.svm.train not found.") + @unittest.skipIf(shutil.which("i.svm.train") is None, "i.svm.train not found.") def test_dont_fail_if_misc_files_missing(self): """Colour file is missing but it should not cause a failure""" sigfile = grass.tempname(10) @@ -215,6 +240,46 @@ def test_dont_fail_if_misc_files_missing(self): misc_file = utils.decode(cpath.value) self.assertTrue(os.path.isfile(misc_file)) + @unittest.skipIf(shutil.which("i.svm.train") is None, "i.svm.train not found.") + def test_rescaling(self): + """Raster values should be rescaled""" + sigfile = grass.tempname(10) + csigdir = ctypes.create_string_buffer(GNAME_MAX) + I_get_signatures_dir(csigdir, I_SIGFILE_TYPE_LIBSVM) + sigdir = utils.decode(csigdir.value) + isvm = SimpleModule( + "i.svm.train", + group=self.group4, + _input=self.rast4, + signaturefile=sigfile, + quiet=True, + ) + self.assertModule(isvm) + self.tmp_sigs.append(sigfile) + cpath = ctypes.create_string_buffer(GPATH_MAX) + G_file_name_misc(cpath, sigdir, "version", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "sig", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "cats", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "colr", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertFalse(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "history", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + G_file_name_misc(cpath, sigdir, "rescale", sigfile, self.mapset_name) + misc_file = utils.decode(cpath.value) + self.assertTrue(os.path.isfile(misc_file)) + with open(misc_file) as rf: + lines = rf.readlines() + val = float(lines[1].strip()) + self.assertTrue(val - 20 < 0.001) + if __name__ == "__main__": test() From d5f376adfb1c5c94d4daf2a3ddd21ffbb5c30621 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Fri, 9 Sep 2022 12:08:22 +0200 Subject: [PATCH 030/123] man: allow register all addons keywords in main Keywords Index (#2529) --- man/build_keywords.py | 59 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/man/build_keywords.py b/man/build_keywords.py index 98926df9643..84fa88f5fcc 100644 --- a/man/build_keywords.py +++ b/man/build_keywords.py @@ -1,7 +1,22 @@ #!/usr/bin/env python3 -# generates keywords.html -# (c) 2013 by the GRASS Development Team, Luca Delucchi +""" +Generates keywords.html file for core and optionally for addons modules. + +Usage: + +Generate core modules keywords HTML page + +python man/build_keywords.py + +Generate core modules and optionally inject addons keywords HTML page + +python man/build_keywords.py + + +@author Luca Delucchi +@author Tomas Zigo - inject addons modules keywords +""" import os import sys @@ -22,18 +37,45 @@ ] path = sys.argv[1] +addons_path = None +if len(sys.argv) >= 3: + addons_path = sys.argv[2] + year = os.getenv("VERSION_DATE") keywords = {} -htmlfiles = glob.glob1(path, "*.html") +htmlfiles = glob.glob(os.path.join(path, "*.html")) +if addons_path: + addons_man_files = glob.glob(os.path.join(addons_path, "*.html")) + htmlfiles.extend(addons_man_files) char_list = {} -for fname in htmlfiles: - fil = open(os.path.join(path, fname)) + +def get_module_man_html_file_path(module): + """Get module manual HTML file path + + :param str module: module manual HTML file name e.g. v.surf.rst.html + + :return str module_path: core/addon module manual HTML file path + """ + if addons_path and module in ",".join(addons_man_files): + module_path = os.path.join(addons_path, module) + module_path = module_path.replace( + os.path.commonpath([path, module_path]), + ".", + ) + else: + module_path = os.path.join(path, module) + return module_path + + +for html_file in htmlfiles: + fname = os.path.basename(html_file) + with open(html_file) as f: + lines = f.readlines() # TODO maybe move to Python re (regex) - lines = fil.readlines() # remove empty lines lines = [x for x in lines if x != "\n"] try: @@ -95,7 +137,10 @@ key, ) for value in sorted(keywords[key]): - keyword_line += ' %s,' % (value, value.replace(".html", "")) + keyword_line += ( + f' ' + f'{value.replace(".html", "")},' + ) keyword_line = keyword_line.rstrip(",") keyword_line += "\n" keywordsfile.write(keyword_line) From e3679469e7e7c7977e202c9f5596bc2173701273 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Sat, 10 Sep 2022 19:00:22 +0200 Subject: [PATCH 031/123] man: use relative path for core modules man HTML page (#2574) --- man/build_keywords.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/build_keywords.py b/man/build_keywords.py index 84fa88f5fcc..5b2b41359b1 100644 --- a/man/build_keywords.py +++ b/man/build_keywords.py @@ -67,7 +67,7 @@ def get_module_man_html_file_path(module): ".", ) else: - module_path = os.path.join(path, module) + module_path = f"./{module}" return module_path From 0073c5509db173f2d1084f0cb9aff985b49fc1c9 Mon Sep 17 00:00:00 2001 From: Ondrej Pesek Date: Sat, 17 Sep 2022 10:35:43 +0200 Subject: [PATCH 032/123] avoid using deprecated locale.getdefaultlocale() * fix #2538 * Use getencoding() where only encoding is needed; getlocale() otherwise --- gui/wxpython/core/gcmd.py | 6 +++++- gui/wxpython/core/gconsole.py | 6 +++++- gui/wxpython/gui_core/forms.py | 18 +++++++++++++++--- gui/wxpython/gui_core/ghelp.py | 6 +++++- gui/wxpython/rlisetup/frame.py | 6 +++++- lib/init/grass.py | 12 ++++++++++-- python/grass/gunittest/multirunner.py | 6 +++++- python/grass/script/utils.py | 6 +++++- utils/mkhtml.py | 6 +++++- 9 files changed, 60 insertions(+), 12 deletions(-) diff --git a/gui/wxpython/core/gcmd.py b/gui/wxpython/core/gcmd.py index 9bea1ee151d..b85874dc242 100644 --- a/gui/wxpython/core/gcmd.py +++ b/gui/wxpython/core/gcmd.py @@ -783,7 +783,11 @@ def GetDefaultEncoding(forceUTF8=False): :return: system encoding (can be None) """ - enc = locale.getdefaultlocale()[1] + try: + # Python >= 3.11 + enc = locale.getencoding() + except AttributeError: + enc = locale.getdefaultlocale()[1] if forceUTF8 and (enc is None or enc == "UTF8"): return "UTF-8" diff --git a/gui/wxpython/core/gconsole.py b/gui/wxpython/core/gconsole.py index fd09dbfedc6..154c71c3dca 100644 --- a/gui/wxpython/core/gconsole.py +++ b/gui/wxpython/core/gconsole.py @@ -408,7 +408,11 @@ def Redirect(self): sys.stdout = self.cmdStdOut sys.stderr = self.cmdStdErr else: - enc = locale.getdefaultlocale()[1] + try: + # Python >= 3.11 + enc = locale.getencoding() + except AttributeError: + enc = locale.getdefaultlocale()[1] if enc: if sys.version_info.major == 2: sys.stdout = codecs.getwriter(enc)(sys.__stdout__) diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index 9a9bb5b9d40..b1c4cd47df6 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -2035,7 +2035,11 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar ) if p.get("value", "") and os.path.isfile(p["value"]): ifbb.Clear() - enc = locale.getdefaultlocale()[1] + try: + # Python >= 3.11 + enc = locale.getencoding() + except AttributeError: + enc = locale.getdefaultlocale()[1] with codecs.open( p["value"], encoding=enc, errors="ignore" ) as f: @@ -2588,7 +2592,11 @@ def OnFileSave(self, event): if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() - enc = locale.getdefaultlocale()[1] + try: + # Python >= 3.11 + enc = locale.getencoding() + except AttributeError: + enc = locale.getdefaultlocale()[1] f = codecs.open(path, encoding=enc, mode="w", errors="replace") try: f.write(text + os.linesep) @@ -2612,7 +2620,11 @@ def OnFileText(self, event): filename = grass.tempfile() win.SetValue(filename) - enc = locale.getdefaultlocale()[1] + try: + # Python >= 3.11 + enc = locale.getencoding() + except AttributeError: + enc = locale.getdefaultlocale()[1] f = codecs.open(filename, encoding=enc, mode="w", errors="replace") try: f.write(text) diff --git a/gui/wxpython/gui_core/ghelp.py b/gui/wxpython/gui_core/ghelp.py index 3a2e18789d1..76f85fb433f 100644 --- a/gui/wxpython/gui_core/ghelp.py +++ b/gui/wxpython/gui_core/ghelp.py @@ -239,7 +239,11 @@ def _pageInfo(self): if not self.langUsed: import locale - loc = locale.getdefaultlocale() + try: + # Python >= 3.11 + loc = locale.getlocale() + except AttributeError: + loc = locale.getdefaultlocale() if loc == (None, None): self.langUsed = _("unknown") else: diff --git a/gui/wxpython/rlisetup/frame.py b/gui/wxpython/rlisetup/frame.py index e2a6a4e7bd8..6b239f8c8b9 100644 --- a/gui/wxpython/rlisetup/frame.py +++ b/gui/wxpython/rlisetup/frame.py @@ -58,7 +58,11 @@ def __init__( self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose) self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk) self._layout() - self.enc = locale.getdefaultlocale()[1] + try: + # Python >= 3.11 + self.enc = locale.getencoding() + except AttributeError: + self.enc = locale.getdefaultlocale()[1] def _layout(self): """Set the layout""" diff --git a/lib/init/grass.py b/lib/init/grass.py index 00fae85e4c2..c34f2176e2c 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -66,7 +66,11 @@ # for wxpath _WXPYTHON_BASE = None -ENCODING = locale.getdefaultlocale()[1] +try: + # Python >= 3.11 + ENCODING = locale.getencoding() +except AttributeError: + ENCODING = locale.getdefaultlocale()[1] if ENCODING is None: ENCODING = "UTF-8" print("Default locale not found, using UTF-8") # intentionally not translatable @@ -1418,7 +1422,11 @@ def set_language(grass_config_dir): "Default locale settings are missing. GRASS running with C locale.\n" ) - language, encoding = locale.getdefaultlocale() + try: + # Python >= 3.11 + language, encoding = locale.getlocale() + except AttributeError: + language, encoding = locale.getdefaultlocale() if not language: sys.stderr.write( "Default locale settings are missing. GRASS running with C locale.\n" diff --git a/python/grass/gunittest/multirunner.py b/python/grass/gunittest/multirunner.py index 1c96ee3dbb3..3bfbb6ad67f 100644 --- a/python/grass/gunittest/multirunner.py +++ b/python/grass/gunittest/multirunner.py @@ -27,7 +27,11 @@ def _get_encoding(): - encoding = locale.getdefaultlocale()[1] + try: + # Python >= 3.11 + encoding = locale.getencoding() + except AttributeError: + encoding = locale.getdefaultlocale()[1] if not encoding: encoding = "UTF-8" return encoding diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index d2f2c631740..ce5aec20a85 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -163,7 +163,11 @@ def __setattr__(self, key, value): def _get_encoding(): - encoding = locale.getdefaultlocale()[1] + try: + # Python >= 3.11 + encoding = locale.getencoding() + except AttributeError: + encoding = locale.getdefaultlocale()[1] if not encoding: encoding = "UTF-8" return encoding diff --git a/utils/mkhtml.py b/utils/mkhtml.py index 494419b39d1..d28e8bb50d7 100644 --- a/utils/mkhtml.py +++ b/utils/mkhtml.py @@ -64,7 +64,11 @@ def _get_encoding(): - encoding = locale.getdefaultlocale()[1] + try: + # Python >= 3.11 + encoding = locale.getencoding() + except AttributeError: + encoding = locale.getdefaultlocale()[1] if not encoding: encoding = "UTF-8" return encoding From e5fbed672d702dcad345d859e0f0f2c2983a287a Mon Sep 17 00:00:00 2001 From: Ondrej Pesek Date: Sat, 17 Sep 2022 12:05:33 +0200 Subject: [PATCH 033/123] grass.py: fix missing parameters in gettext.install() fix #2507 --- lib/init/grass.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index c34f2176e2c..f3225f9e26e 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -1568,10 +1568,7 @@ def set_language(grass_config_dir): del os.environ["LC_ALL"] # Remove LC_ALL to not override LC_NUMERIC # From now on enforce the new language - if encoding: - gettext.install("grasslibs", gpath("locale"), codeset=encoding) - else: - gettext.install("grasslibs", gpath("locale")) + gettext.install("grasslibs", gpath("locale")) def lock_mapset(mapset_path, force_gislock_removal, user): From ed05dcce1f097aa83dfd04b17e66d8b51b9d9d93 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Sun, 18 Sep 2022 18:53:31 +0200 Subject: [PATCH 034/123] wxGUI/forms: fix LayersList widget binding check/uncheck event method (#2495) `CheckListCtrlMixin` class is obsolete and `OnCheckItem` method doesn't work with wxPython >= 4.1.1 version. Instead of that, an event `wx.EVT_LIST_ITEM_CHECKED`, `wx.EVT_LIST_ITEM_UNCHECKED` is binded to the widget `LayersList` widget. --- gui/wxpython/gui_core/forms.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index b1c4cd47df6..1465aca4da8 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -2266,7 +2266,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar ) p["wxId"] = [self.win1.GetId()] - def OnCheckItem(index, flag): + def OnCheckItem(index=None, flag=None, event=None): layers = list() geometry = None for layer, match, listId in self.win1.GetLayers(): @@ -2281,7 +2281,13 @@ def OnCheckItem(index, flag): # TODO: v.import has no geometry option self.OnUpdateValues() # TODO: replace by signal - self.win1.OnCheckItem = OnCheckItem + from core.globalvar import CheckWxVersion + + if CheckWxVersion([4, 1, 0]): + self.win1.Bind(wx.EVT_LIST_ITEM_CHECKED, OnCheckItem) + self.win1.Bind(wx.EVT_LIST_ITEM_UNCHECKED, OnCheckItem) + else: + self.win1.OnCheckItem = OnCheckItem elif prompt == "sql_query": win = gselect.SqlWhereSelect(parent=which_panel, param=p) From 06008236165b052f3c304dd54d0d841023c1aea6 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Mon, 19 Sep 2022 15:39:06 +0200 Subject: [PATCH 035/123] wxGUI/modules: fix import SQLite geometry data (#2491) --- gui/wxpython/core/utils.py | 1 + gui/wxpython/gui_core/gselect.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gui/wxpython/core/utils.py b/gui/wxpython/core/utils.py index f34d4315627..ec0520c7ae6 100644 --- a/gui/wxpython/core/utils.py +++ b/gui/wxpython/core/utils.py @@ -669,6 +669,7 @@ def _parseFormats(output, writableOnly=False): if name in ( "PostgreSQL", "SQLite", + "SQLite / Spatialite", "ODBC", "ESRI Personal GeoDatabase", "Rasterlite", diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index 92f26eecf24..68b670d3c1f 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -2167,7 +2167,7 @@ def GetDsn(self): def SetDatabase(self, db): """Update database panel.""" sizer = self.dbPanel.GetSizer() - showBrowse = db in ("SQLite", "Rasterlite") + showBrowse = db in ("SQLite", "SQLite / Spatialite", "Rasterlite") showDirbrowse = db in ("FileGDB") showChoice = db in ( "PostgreSQL", From ed922a4f670a1c1ebdc7e3519fb66fa0a129c2f3 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Wed, 21 Sep 2022 20:58:44 +0200 Subject: [PATCH 036/123] general/g.mapsets: fix write MAPSETS without additional empty new line (#2586) Current behavior: ``` GRASS nc_spm_08_grass7/landsat:~ > g.mapsets operation=set mapset=landsat GRASS nc_spm_08_grass7/landsat:~ > cat -e "$(g.gisenv get="GISDBASE")/\ $(g.gisenv get="LOCATION_NAME")/$(g.gisenv get="MAPSET")/SEARCH_PATH" landsat$ $ ``` Expected behavior: ``` GRASS nc_spm_08_grass7/landsat:~ > g.mapsets operation=set mapset=landsat GRASS nc_spm_08_grass7/landsat:~ > cat -e "$(g.gisenv get="GISDBASE")/\ $(g.gisenv get="LOCATION_NAME")/$(g.gisenv get="MAPSET")/SEARCH_PATH" landsat$ ``` --- general/g.mapsets/main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 1e20f52f67a..e9584dc0f06 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -297,7 +297,6 @@ int main(int argc, char *argv[]) */ no_tokens = G_number_of_tokens(tokens); - for (n = 0; n < no_tokens; n++) { skip = 0; for (i = n; i < no_tokens; i++) { @@ -331,9 +330,12 @@ void append_mapset(char **path, const char *mapset) int len = (*path == NULL ? 0 : strlen(*path)); *path = (char *)G_realloc(*path, len + strlen(mapset) + 2); - if (!len) + if (!len) { *path[0] = '\0'; - strcat(*path, mapset); - strcat(*path, " "); + strcat(*path, mapset); + } else { + strcat(*path, " "); + strcat(*path, mapset); + } return; } From 14a456a24d1c73e7db6ea793d3e809f86e051a75 Mon Sep 17 00:00:00 2001 From: Stefan Blumentrath Date: Sun, 2 Oct 2022 22:57:53 +0200 Subject: [PATCH 037/123] g.extension: use copytree from shutil for py >= 3.8 (#2592) --- scripts/g.extension/g.extension.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py index 5db82e97b19..8f0a3947e5b 100644 --- a/scripts/g.extension/g.extension.py +++ b/scripts/g.extension/g.extension.py @@ -164,7 +164,13 @@ import tempfile import json import xml.etree.ElementTree as etree -from distutils.dir_util import copy_tree + +if sys.version_info.major == 3 and sys.version_info.minor < 8: + from distutils.dir_util import copy_tree +else: + from functools import partial + + copy_tree = partial(shutil.copytree, dirs_exist_ok=True) from six.moves.urllib import request as urlrequest from six.moves.urllib.error import HTTPError, URLError From 391dcbd81c5ef4a85565313f9a435115f873be4e Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Mon, 3 Oct 2022 11:34:23 +0200 Subject: [PATCH 038/123] SEO and manuals: add viewport and page language (#2591) This PR addresses #2589 (SEO problems on mobile devices): - Google: addresses "Page isn't usable on mobile" - "Viewport not set" - https://search.google.com/search-console/mobile-usability?resource_id=http%3A%2F%2Fgrass.osgeo.org%2F&hl=en - see: https://support.google.com/webmasters/answer/9063469#viewport_not_configured - Bing: addresses "The page is missing meta language information" - https://www.bing.com/webmasters/seoreports?siteUrl=https%3A%2F%2Fgrass.osgeo.org%2F&ruleId=39 Manual pages generated with this PR applied are validated correctly at https://validator.w3.org/ --- REQUIREMENTS.html | 2 ++ db/drivers/mysql/grass-mesql.html | 6 ++++-- general/g.setproj/g.setproj.html | 6 ++++-- lib/gis/parser_html.c | 8 +++++++- man/build_html.py | 2 ++ raster/r.li/r.li.html | 6 ++++-- utils/mkhtml.py | 2 ++ utils/module_synopsis.sh | 6 ++++-- 8 files changed, 29 insertions(+), 9 deletions(-) diff --git a/REQUIREMENTS.html b/REQUIREMENTS.html index b3f420b9ff4..e22ac0837d1 100644 --- a/REQUIREMENTS.html +++ b/REQUIREMENTS.html @@ -4,6 +4,8 @@ REQUIREMENTS to compile GRASS GIS 8 + + diff --git a/db/drivers/mysql/grass-mesql.html b/db/drivers/mysql/grass-mesql.html index 34b0fd700a9..369c4f243ad 100644 --- a/db/drivers/mysql/grass-mesql.html +++ b/db/drivers/mysql/grass-mesql.html @@ -2,8 +2,10 @@ GRASS-MySQL embedded driver - GRASS GIS manual - - + + + + diff --git a/general/g.setproj/g.setproj.html b/general/g.setproj/g.setproj.html index 014eec18c99..3b9b4e8fc7f 100644 --- a/general/g.setproj/g.setproj.html +++ b/general/g.setproj/g.setproj.html @@ -2,8 +2,10 @@ g.setproj - GRASS GIS manual - - + + + + diff --git a/lib/gis/parser_html.c b/lib/gis/parser_html.c index 629945020a6..477b78fba5f 100644 --- a/lib/gis/parser_html.c +++ b/lib/gis/parser_html.c @@ -3,7 +3,7 @@ \brief GIS Library - Argument parsing functions (HTML output) - (C) 2001-2009, 2011-2020 by the GRASS Development Team + (C) 2001-2022 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. @@ -45,6 +45,12 @@ void G__usage_html(void) fprintf(stdout, "\n\n"); fprintf(stdout, " \n"); + fprintf(stdout, + " \n"); + fprintf(stdout, + " \n"); + fprintf(stdout, + " \n"); fprintf(stdout, " %s - GRASS GIS manual\n", st->pgm_name); fprintf(stdout, " pgm_name); if (st->module_info.description) diff --git a/man/build_html.py b/man/build_html.py index ddbc02311d0..c0c97766d97 100644 --- a/man/build_html.py +++ b/man/build_html.py @@ -39,6 +39,8 @@ ${title} - GRASS GIS Manual + + """ ) diff --git a/raster/r.li/r.li.html b/raster/r.li/r.li.html index 6bd255b0968..e84996f83a0 100644 --- a/raster/r.li/r.li.html +++ b/raster/r.li/r.li.html @@ -2,8 +2,10 @@ r.li - GRASS GIS manual - - + + + +

diff --git a/utils/mkhtml.py b/utils/mkhtml.py index d28e8bb50d7..f39abbf168b 100644 --- a/utils/mkhtml.py +++ b/utils/mkhtml.py @@ -375,6 +375,8 @@ def get_last_git_commit(src_dir, addon_path, is_addon): + +
diff --git a/utils/module_synopsis.sh b/utils/module_synopsis.sh index b3cef7a7e6f..b60b2b37245 100755 --- a/utils/module_synopsis.sh +++ b/utils/module_synopsis.sh @@ -196,8 +196,10 @@ cat <"${TMP}.html" $(g.version | cut -f1 -d'(') Command list - - + + + + From 4833a0e08ef091686c74d003d0228b520bee9575 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Tue, 4 Oct 2022 23:21:48 -0400 Subject: [PATCH 039/123] v.out.vtk: Output double data type instead of float (#2562) Geometric information in the VTK Polydata dataset output of the v.out.vtk function are now saved as datatype double instead of float which is more suitable considering the amount of digits in geographic coordinates. The 'POINTS n dataType' line now uses double dataType (float, double, int and more is allowed). Fixes #864. Actual code change written by Brad ReDacted. Co-authored-by: Brad ReDacted --- vector/v.out.vtk/main.c | 7 +++---- vector/v.out.vtk/writeVTK.c | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/vector/v.out.vtk/main.c b/vector/v.out.vtk/main.c index 3a65ed520c9..0f01bc7d505 100644 --- a/vector/v.out.vtk/main.c +++ b/vector/v.out.vtk/main.c @@ -66,8 +66,7 @@ int main(int argc, char *argv[]) dp_opt->key = "precision"; dp_opt->type = TYPE_INTEGER; dp_opt->required = NO; - dp_opt->description = - _("Number of significant digits (floating point only)"); + dp_opt->description = _("Number of significant digits"); scale = G_define_option(); scale->key = "zscale"; @@ -151,8 +150,8 @@ int main(int argc, char *argv[]) if (dp_opt->answer) { if (sscanf(dp_opt->answer, "%d", &dp) != 1) G_fatal_error(_("Failed to interpret 'dp' parameter as an integer")); - if (dp > 8 || dp < 0) - G_fatal_error(_("dp has to be from 0 to 8")); + if (dp > 16 || dp < 0) + G_fatal_error(_("dp has to be from 0 to 16")); } else { dp = 8; /*This value is taken from the lib settings in G_feature_easting */ diff --git a/vector/v.out.vtk/writeVTK.c b/vector/v.out.vtk/writeVTK.c index 5288242e50c..58e132d602e 100644 --- a/vector/v.out.vtk/writeVTK.c +++ b/vector/v.out.vtk/writeVTK.c @@ -200,7 +200,7 @@ int write_vtk_points(FILE * ascii, struct Map_info *Map, VTKInfo * info, /************************************************/ - fprintf(ascii, "POINTS %i float\n", info->maxnumpoints); + fprintf(ascii, "POINTS %i double\n", info->maxnumpoints); /*For every available vector type */ for (k = 0; k < typenum; k++) { From b69b137c3d86a34fc97f308594d992aeb2eedd64 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Thu, 6 Oct 2022 09:11:03 -0400 Subject: [PATCH 040/123] grass.pygrass: VisibleMapset: fix reading search path (#2584) * handle missing search path file, do not write since this is only reading * use text mode for writing/reading * write newline after each mapset --- python/grass/pygrass/gis/__init__.py | 37 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/python/grass/pygrass/gis/__init__.py b/python/grass/pygrass/gis/__init__.py index c14ad85fbef..b9614577c30 100644 --- a/python/grass/pygrass/gis/__init__.py +++ b/python/grass/pygrass/gis/__init__.py @@ -20,7 +20,6 @@ from grass.pygrass.errors import GrassError from grass.script.utils import encode, decode from grass.pygrass.utils import getenv -from grass.pygrass.gis.region import Region test_vector_name = "Gis_test_vector" test_raster_name = "Gis_test_raster" @@ -440,15 +439,14 @@ def __iter__(self): def read(self): """Return the mapsets in the search path""" - with open(self.spath, "ab+") as f: - lines = f.readlines() - if lines: - return [decode(line.strip()) for line in lines] - lns = [ - "PERMANENT", - ] - self._write(lns) - return lns + try: + with open(self.spath, "r") as f: + lines = f.readlines() + if lines: + return [line.strip() for line in lines] + return [self.mapset] + except FileNotFoundError: + return [self.mapset, "PERMANENT"] def _write(self, mapsets): """Write to SEARCH_PATH file the changes in the search path @@ -456,9 +454,12 @@ def _write(self, mapsets): :param mapsets: a list of mapset's names :type mapsets: list """ - with open(self.spath, "wb+") as f: - ms = [decode(m) for m in self.location.mapsets()] - f.write(b"\n".join([encode(m) for m in mapsets if m in ms])) + with open(self.spath, "w") as f: + ms = self.location.mapsets() + for m in mapsets: + if m in ms: + f.write(m) + f.write("\n") def add(self, mapset): """Add a mapset to the search path @@ -468,7 +469,7 @@ def add(self, mapset): """ if mapset not in self.read() and mapset in self.location: with open(self.spath, "a+") as f: - f.write("\n%s" % mapset) + f.write("%s\n" % mapset) else: raise TypeError("Mapset not found") @@ -488,10 +489,10 @@ def extend(self, mapsets): :param mapsets: a list of mapset's names :type mapsets: list """ - ms = [decode(m) for m in self.location.mapsets()] - final = [decode(m) for m in self.read()] - mapsets = [decode(m) for m in mapsets] - final.extend([m for m in mapsets if m in ms and m not in final]) + final = self.read() + final.extend( + [m for m in mapsets if m in self.location.mapsets() and m not in final] + ) self._write(final) def reset(self): From a56aa24ad8cf3bb4e9de9cbfebb10df4a969293a Mon Sep 17 00:00:00 2001 From: Wolf Bergenheim Date: Fri, 7 Oct 2022 05:11:46 +0200 Subject: [PATCH 041/123] init: Fix sudo message on Ubuntu (#2532) Create /.sudo_as_admin_successful when $HOME/.sudo_as_admin_successful exists to avoid message about sudo for the a Bash instance for each session. Contains several unrelated Black changes. Fixes #753. --- lib/init/grass.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index f3225f9e26e..3547107f2c6 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -649,11 +649,7 @@ def create_fallback_session(gisrc, tmpdir): """Creates fallback temporary session""" # Create temporary location set_mapset( - gisrc=gisrc, - geofile="XY", - create_new=True, - tmp_location=True, - tmpdir=tmpdir, + gisrc=gisrc, geofile="XY", create_new=True, tmp_location=True, tmpdir=tmpdir ) @@ -1762,9 +1758,7 @@ def script_path(batch_job): script_in_addon_path = None if "GRASS_ADDON_BASE" in os.environ: script_in_addon_path = os.path.join( - os.environ["GRASS_ADDON_BASE"], - "scripts", - batch_job[0], + os.environ["GRASS_ADDON_BASE"], "scripts", batch_job[0] ) if script_in_addon_path and os.path.exists(script_in_addon_path): batch_job[0] = script_in_addon_path @@ -1777,8 +1771,7 @@ def script_path(batch_job): proc = Popen(batch_job, shell=False, env=os.environ) except OSError as error: error_message = _("Execution of <{cmd}> failed:\n" "{error}").format( - cmd=batch_job_string, - error=error, + cmd=batch_job_string, error=error ) # No such file or directory if error.errno == errno.ENOENT: @@ -2044,6 +2037,21 @@ def sh_like_startup(location, location_name, grass_env_file, sh): """.format( sh_history=sh_history ) + # Ubuntu sudo creates a file .sudo_as_admin_successful and bash checks + # for this file in the home directory from /etc/bash.bashrc and prints a + # message if it's not detected. This can be suppressed with either + # creating the file ~/.sudo_as_admin_successful (it's always empty) or + # by creating a file ~/.hushlogin (also an empty file) + # Here we create the file in the Mapset directory if it exists in the + # user's home directory. + sudo_success_file = ".sudo_as_admin_successful" + if os.path.exists(os.path.join(userhome, sudo_success_file)): + try: + # Open with append so that if the file already exists there + # isn't any error. + fh = open(os.path.join(home, sudo_success_file), "a") + finally: + fh.close() # double curly brackets means single one for format function # setting LOCATION for backwards compatibility @@ -2564,8 +2572,7 @@ def main(): from grass.grassdb.checks import can_start_in_mapset last_mapset_usable = can_start_in_mapset( - mapset_path=last_mapset_path, - ignore_lock=params.force_gislock_removal, + mapset_path=last_mapset_path, ignore_lock=params.force_gislock_removal ) debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: From 7503a325f78e71d69910fdda5a5a7b341ed73021 Mon Sep 17 00:00:00 2001 From: Ondrej Pesek Date: Fri, 7 Oct 2022 09:21:31 +0200 Subject: [PATCH 042/123] contributing: Validate Markdown files * linter: turn Markdown validation on * Markdown files cleanup --- .github/workflows/README.md | 2 +- .github/workflows/super-linter.yml | 2 +- CONTRIBUTING.md | 42 ++- INSTALL.md | 50 ++-- README.md | 12 +- doc/development/rfc/PSC_guidelines.md | 20 +- .../rfc/language_standards_support.md | 17 +- .../legal_aspects_of_code_contributions.md | 43 ++- doc/development/rfc/migration_github.md | 137 +++++---- doc/howto_release.md | 52 ++-- doc/infrastructure.md | 263 +++++++++--------- doc/notebooks/README.md | 18 +- docker/README.md | 18 +- docker/testdata/README.md | 2 + macosx/ReadMe.md | 36 +-- mswindows/external/rbatch/batchfiles.md | 38 +-- python/grass/gunittest/README.md | 4 +- python/libgrass_interface_generator/README.md | 42 +-- testsuite/README.md | 12 +- 19 files changed, 418 insertions(+), 392 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index a85a037fbad..eb549554286 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -4,7 +4,7 @@ Run locally using Docker: -``` +```bash docker run --rm -e RUN_LOCAL=true -e VALIDATE_PERL=true -v $PWD:/tmp/lint github/super-linter ``` diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index fc44d947000..b43e5167d11 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -31,7 +31,7 @@ jobs: VALIDATE_JAVASCRIPT_ES: true VALIDATE_JAVASCRIPT_STANDARD: false VALIDATE_JSON: true - VALIDATE_MD: false + VALIDATE_MD: true VALIDATE_PERL: true VALIDATE_POWERSHELL: true VALIDATE_XML: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c137d983bc..56ed195af06 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,36 +23,34 @@ GRASS GIS developer mailing list. of the GitHub interface). * Clone your fork (use HTTPS or SSH URL, here we will use HTTPS): -``` -git clone https://github.com/your_GitHub_account/grass.git +```bash +git clone git@github.com:your_GH_account/grass.git ``` * Enter the directory -``` +```bash cd grass/ ``` * Add main GRASS GIS repository as "upstream" (use HTTPS URL): -``` +```bash git remote add upstream https://github.com/OSGeo/grass ``` * Your remotes now should be "origin" which is your fork and "upstream" which is this main GRASS GIS repository. You can confirm that using: -``` +```bash git remote -v ``` * You should see something like: -``` -origin https://github.com/your_GH_account/grass.git (fetch) -origin https://github.com/your_GH_account/grass.git (push) -upstream https://github.com/OSGeo/grass.git (fetch) -upstream https://github.com/OSGeo/grass.git (push) +```bash +origin git@github.com:your_GH_account/grass.git (fetch) +origin git@github.com:your_GH_account/grass.git (push) ``` For the following workflow, it is important that @@ -64,20 +62,20 @@ and "origin" to your fork * Make sure your are using the _main_ branch to create the new branch: -``` -git switch main +```bash +git checkout main ``` * Download updates from all branches from the _upstream_ remote: -``` +```bash git fetch upstream ``` * Update your local _main_ branch to match the _main_ branch in the _upstream_ repository: -``` +```bash git rebase upstream/main ``` @@ -90,19 +88,19 @@ rebase or merge happens). If `rebase` fails with "error: cannot rebase: You have unstaged changes...", then move your uncommitted local changes to "stash" using: -``` +```bash git stash ``` * Now you can rebase: -``` +```bash git rebase upstream/main ``` * Get the changes back from stash: -``` +```bash git stash pop ``` @@ -113,7 +111,7 @@ based on it. * Create a new feature branch and switch to it: -``` +```bash git checkout -b new-feature ``` @@ -142,21 +140,21 @@ request comment. Note that there are some steps you can do locally to improve your code. For Python, run `black .` to apply standardized formatting. You can -also run linter tools such as Pylint which will suggest different improvements +also run linter tools such as Pylint which will suggest different improvements to your code. ### Committing * Add files to the commit (changed ones or new ones): -``` +```bash git add file1 git add file2 ``` * Commit the change (first word is the module name): -``` +```bash git commit -m "module: added a new feature" ``` @@ -164,7 +162,7 @@ git commit -m "module: added a new feature" * Push your local feature branch to your fork: -``` +```bash git push origin new-feature ``` diff --git a/INSTALL.md b/INSTALL.md index aff515781dd..ca7badd398b 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -65,7 +65,7 @@ For Solaris, see hints below. The command, -``` +```bash ./configure --help ``` @@ -77,13 +77,13 @@ distributions, FreeBSD, AIX, etc) are available at: First step of the compilation (-g for debugging, or -O2 for optimization): -``` +```bash CFLAGS="-g -Wall" ./configure ``` Explanation of make targets: -``` +```text make install - installs the binary make bindist - make a binary package with install script @@ -104,7 +104,7 @@ make pdfdocs - generate programmer's documentation as PDF files Next step is the compilation itself: -``` +```bash make ``` @@ -115,13 +115,13 @@ install program (AC_PROG_INSTALL ignores versions which are known to have problems), you need to ensure that $srcdir is an absolute path, by using e.g.: -``` +```bash `pwd`/configure ... ``` or: -``` +```bash ./configure --srcdir=`pwd` ... ``` @@ -132,7 +132,7 @@ Note when using a compiler different from "gcc": By setting environment variables, the compiler names can be defined (C and C++): -``` +```bash CC=cc CPP=cpp ./configure ... ``` @@ -141,7 +141,7 @@ CC=cc CPP=cpp ./configure ... To successfully compile GRASS on 64bit platforms, the required FFTW2 library has to be compiled with -fPIC flag: -``` +```bash #this applies to FFTW3, not to GRASS GIS: cd fftw-3.3.4/ CFLAGS="-fPIC" ./configure @@ -152,7 +152,7 @@ make install To fully enable 64bit library usage for GRASS on 64bit platforms, the following additional parameters are recommended/required: -``` +```bash ./configure \ --enable-64bit \ --with-libs=/usr/lib64 \ @@ -165,25 +165,25 @@ See also CODE OPTIMIZATION below. After compilation, the resulting code is stored in the directory -``` +```bash ./dist.$ARCH ``` and the scripts (grass, ...) in -``` +```bash ./bin.$ARCH ``` To run GRASS, simply start -``` +```bash ./bin.$ARCH/grass ``` or run -``` +```bash make install grass ``` @@ -212,7 +212,7 @@ GitHub, you have to perform a few steps. In general: In detail: -``` +```bash cd /where/your/grass-source-code/lives/ git fetch --all git merge upstream/main @@ -229,7 +229,7 @@ To compile (self-made) GRASS modules or to compile modified modules at least the GRASS libraries have to be compiled locally. This is done by launching: -``` +```bash make libs ``` @@ -237,19 +237,19 @@ Then change into the module's directory and launch the "make" command. The installation can be either done with "make install" from the main source code directory or locally with -``` +```bash "INST_NOW=y make" ``` You may want to define an alias for this: -``` +```bash alias gmake='INST_NOW=y make' ``` Then simply compile/install the current module with -``` +```bash gmake ``` @@ -262,13 +262,13 @@ path(s) in the Makefile to absolute path(s). If you would like to set compiler optimisations, for a possibly faster binary, type (don't enter a ";" anywhere): -``` +```bash CFLAGS=-O ./configure ``` or, -``` +```bash setenv CFLAGS -O ./configure ``` @@ -278,7 +278,7 @@ supports this (note: O is the letter, not zero). Using the "gcc" compiler, you can also specify processor specific flags (examples, please suggest better settings to us): -``` +```bash CFLAGS="-mcpu=athlon -O2" # AMD Athlon processor with code optimisations CFLAGS="-mcpu=pentium" # Intel Pentium processor CFLAGS="-mcpu=pentium4" # Intel Pentium4 processor @@ -292,7 +292,7 @@ by the local machine at GCC runtime including -mtune. To find out optional CFLAGS for your platform, enter: -``` +```bash gcc -dumpspecs ``` @@ -301,7 +301,7 @@ See also: A real fast GRASS version (and small binaries) will be created with LDFLAGS set to "stripping" (but this disables debugging): -``` +```bash CFLAGS="-O2 -mcpu= -Wall" LDFLAGS="-s" ./configure ``` @@ -317,7 +317,7 @@ the source code. The `-g` and `-Wall` compiler flags are often useful for assisting debugging: -``` +```bash CFLAGS="-g -Wall" ./configure ``` @@ -329,7 +329,7 @@ See also the file ./doc/debugging.txt and the Wiki page GRASS GIS includes improved support for reading and writing large files (> 2GB) if it is possible in your operating system. If you compile with -``` +```bash configure [...] --enable-largefile ``` diff --git a/README.md b/README.md index 665472082eb..9777dd1ff7b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# GRASS GIS Repository + [![Build Status](https://travis-ci.com/OSGeo/grass.svg?branch=main)](https://travis-ci.com/OSGeo/grass) [![GCC C/C++ standards check](https://github.com/OSGeo/grass/workflows/GCC%20C/C++%20standards%20check/badge.svg)](https://github.com/OSGeo/grass/actions?query=workflow%3A%22GCC+C%2FC%2B%2B+standards+check%22) [![Python code quality check](https://github.com/OSGeo/grass/workflows/Python%20code%20quality%20check/badge.svg)](https://github.com/OSGeo/grass/actions?query=workflow%3A%22Python+code+quality+check%22) @@ -8,8 +10,6 @@ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5176030.svg)](https://doi.org/10.5281/zenodo.5176030) [![Join the chat at https://gitter.im/grassgis/community](https://badges.gitter.im/grassgis/community.svg)](https://gitter.im/grassgis/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -# GRASS GIS Repository - ## Description GRASS GIS ([https://grass.osgeo.org/](https://grass.osgeo.org/)) is @@ -43,7 +43,7 @@ Yes, you should really read [INSTALL.md](INSTALL.md). In addition, there are det Build a docker image using the downloaded source code (run this in the directory containing the source code): -``` +```bash docker build -t grassgis . ``` @@ -51,7 +51,7 @@ A test run (assuming you have the existing GRASS GIS test location; it can be downloaded from [here](https://grass.osgeo.org/sampledata/north_carolina/nc_basic_spm_grass7.zip)) -``` +```bash # case 1: launching in the grassdata directory in which the location is stored: docker run -it --rm --user=$(id -u):$(id -g) --volume $(pwd):/data \ --env HOME=/data/ grassgis grass --text nc_basic_spm_grass7/user1 \ @@ -68,7 +68,7 @@ Note that the first `grassgis` is the name of the image while the second To run the tests (again assuming local location): -``` +```bash docker run -it --rm --user=$(id -u):$(id -g) \ --volume /your/test/grassdata/:/data --env HOME=/data/ -w /code/grass \ grassgis grass /data/nc_basic_spm_grass7/PERMANENT --exec \ @@ -81,6 +81,6 @@ encounter problems as the local configuration and the locally compiled files are copied to and used in the Docker image. To make sure you don't have this issue, clean all the compiled files from the source code: -``` +```bash make distclean ``` diff --git a/doc/development/rfc/PSC_guidelines.md b/doc/development/rfc/PSC_guidelines.md index 5691a9fc60f..0502e78a186 100644 --- a/doc/development/rfc/PSC_guidelines.md +++ b/doc/development/rfc/PSC_guidelines.md @@ -39,9 +39,9 @@ project. The quality control mechanisms, which are the responsibility of the PSC, currently include: - * Maintaining submitter guidelines and making all developers aware of them. - * Granting write access to the source code repository for new developers. - * Enforcing the submitter guidelines, with the ultimate sanction against non-compliance being removal of write access to the source code repository. +* Maintaining submitter guidelines and making all developers aware of them. +* Granting write access to the source code repository for new developers. +* Enforcing the submitter guidelines, with the ultimate sanction against non-compliance being removal of write access to the source code repository. In general, once write access has been granted, developers are allowed to make changes to the codebase as they see fit. For controversial or @@ -76,11 +76,11 @@ The PSC will share responsibility and make decisions over issues related to the management of the overall direction of the GRASS project and external visibility, etc. These include, but are not limited to: - * Release Cycles - * Project infrastructure - * Website Maintenance - * Promotion and Public Relations - * Other issues as they become relevant +* Release Cycles +* Project infrastructure +* Website Maintenance +* Promotion and Public Relations +* Other issues as they become relevant It is the responsibility of the PSC to ensure that issues critical to the future of the GRASS project are adequately attended to. This may involve @@ -105,8 +105,8 @@ break down of decision-making, or in case of disputes over voting. The following issue(s) *must* have a vote called before a decision is reached: - * Granting source code repository write access for new developers - * Selection of a committee Chair +* Granting source code repository write access for new developers +* Selection of a committee Chair ## Composition of the Committee diff --git a/doc/development/rfc/language_standards_support.md b/doc/development/rfc/language_standards_support.md index 8be7292f2f2..32ebcb8d9e6 100644 --- a/doc/development/rfc/language_standards_support.md +++ b/doc/development/rfc/language_standards_support.md @@ -23,7 +23,22 @@ The advantage of having clearly stated policy on language standard requirements/ It should be emphasized that existing GRASS GIS C and C++ code compiles also with C17 and C++17. There is therefore no need to modernize it the way it was done to C in the 2000’s. Nevertheless, conforming to newer standards may provide better cross platform support and possibly safer code. -Regarding C, there are three standards that may be considered: C99, C11 and C17. C99 never really reached full support on key platforms, this is particularly the case for Windows ([Visual Studio 2013](https://devblogs.microsoft.com/cppblog/c99-library-support-in-visual-studio-2013/)). Partly in consequence of this lack of support for some C99 features, the C11 standard was made less strict: making some C99 mandatory features optional. Thus, from autumn 2020 even [MSVC complies to C11](https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/) core feature support. Starting with [GCC 4.9](https://gcc.gnu.org/wiki/C11Status) it had “substantially complete” support for C11, Clang from [version 3.1](https://releases.llvm.org/3.1/docs/ClangReleaseNotes.html). [C17](https://en.wikipedia.org/wiki/C17_(C_standard_revision)), on the other hand, doesn’t add new features compared to C11. Its difference is more interesting from compiler point of view, whereas code “good for C11” is good for C17. +Regarding C, there are three standards that may be considered: C99, C11 and +C17. C99 never really reached full support on key platforms, this is +particularly the case for Windows +([Visual Studio 2013](https://devblogs.microsoft.com/cppblog/c99-library-support-in-visual-studio-2013/)). +Partly in consequence of this lack of support for some C99 features, the C11 +standard was made less strict: making some C99 mandatory features optional. +Thus, from autumn 2020 even +[MSVC complies to C11](https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/) +core feature support. Starting with +[GCC 4.9](https://gcc.gnu.org/wiki/C11Status) it had “substantially +complete” support for C11, Clang from +[version 3.1](https://releases.llvm.org/3.1/docs/ClangReleaseNotes.html). +[C17](https://en.wikipedia.org/wiki/C17_(C_standard_revision)), on the other +hand, doesn’t add new features compared to C11. Its difference is more +interesting from compiler point of view, whereas code “good for C11” is +good for C17. Regarding C++, there are the C++98, C++03, C++11, C++14 and C++17 standards to consider. The platform and compiler support for all of these are significantly better. However, C++11 is at this date in general considered the standard and until compelling reasons argue otherwise, the C++11 standard should be policy of the GRASS GIS project. diff --git a/doc/development/rfc/legal_aspects_of_code_contributions.md b/doc/development/rfc/legal_aspects_of_code_contributions.md index 11f18752544..4db466a412b 100644 --- a/doc/development/rfc/legal_aspects_of_code_contributions.md +++ b/doc/development/rfc/legal_aspects_of_code_contributions.md @@ -42,30 +42,29 @@ Committers should adhere to the following guidelines, and may be personally legally liable for improperly contributing code to the source repository: - * Make sure the contributor (and possibly employer) is aware of the - contribution terms. - * Code coming from a source other than the contributor (such as - adapted from another project) should be clearly marked as to the - original source, copyright holders, license terms and so forth. This - information can be in the file headers, but should also be added to - the project licensing file if not exactly matching normal project - licensing (grass/COPYRIGHT.txt). - * Existing copyright headers and license text should never be stripped - from a file. If a copyright holder wishes to give up copyright they - must do so in writing to the GRASS [PSC](https://trac.osgeo.org/grass/wiki/PSC) before copyright messages - are removed. If license terms are changed, it has to be by agreement - (written in email is ok) of the copyright holders. - * When substantial contributions are added to a file (such as - substantial patches) the author/contributor should be added to the - list of copyright holders for the file in the file header. - * If there is uncertainty about whether a change is proper to - contribute to the code base, please seek more information from the - Project Steering Committee, other GRASS developers or the OSGeo - foundation legal counsel. +* Make sure the contributor (and possibly employer) is aware of the + contribution terms. +* Code coming from a source other than the contributor (such as + adapted from another project) should be clearly marked as to the + original source, copyright holders, license terms and so forth. This + information can be in the file headers, but should also be added to + the project licensing file if not exactly matching normal project + licensing (grass/COPYRIGHT.txt). +* Existing copyright headers and license text should never be stripped + from a file. If a copyright holder wishes to give up copyright they + must do so in writing to the GRASS [PSC](https://trac.osgeo.org/grass/wiki/PSC) before copyright messages + are removed. If license terms are changed, it has to be by agreement + (written in email is ok) of the copyright holders. +* When substantial contributions are added to a file (such as + substantial patches) the author/contributor should be added to the + list of copyright holders for the file in the file header. +* If there is uncertainty about whether a change is proper to + contribute to the code base, please seek more information from the + Project Steering Committee, other GRASS developers or the OSGeo + foundation legal counsel. Questions regarding GRASS GIS should be directed to the GRASS Development Team at the following address: -Internet: - http://grass.osgeo.org/home/contact-us/ +Internet: diff --git a/doc/development/rfc/migration_github.md b/doc/development/rfc/migration_github.md index ca5f7551e43..1df1ab6b068 100644 --- a/doc/development/rfc/migration_github.md +++ b/doc/development/rfc/migration_github.md @@ -12,13 +12,13 @@ The centralized source code management system Subversion (SVN) has served the GR ## Background information of git migration - * For background and aims, see - * https://trac.osgeo.org/grass/wiki/GitMigration - * Results of a survey performed in early 2019: - * https://docs.google.com/forms/d/1BoTFyZRNebqVX98A3rh5GpUS2gKFfmuim78gbradDjc/viewanalytics - * Technical discussions - * svn -> git test migration ongoing, see [#3722](https://trac.osgeo.org/grass/ticket/3722) - * trac -> github test issue migration ongoing, see [#3789](https://trac.osgeo.org/grass/ticket/3789) +* For background and aims, see + * +* Results of a survey performed in early 2019: + * +* Technical discussions + * svn -> git test migration ongoing, see [#3722](https://trac.osgeo.org/grass/ticket/3722) + * trac -> github test issue migration ongoing, see [#3789](https://trac.osgeo.org/grass/ticket/3789) ## New GitHub repositories @@ -26,21 +26,19 @@ Since migration is a huge effort, massive work on converting the existing source The following new GitHub repositories have been [created](https://github.com/grass-svn2git). Note that the "cut-off" date of the main **grass** repository does not correspond to the first upload to CSV which was then migrated to SVN. The repositories **grass** and **grass-legacy** overlap in time since they contain different branches: - * repository **grass** - * Source code from 2008 (as the starting commit r31142 was selected, i.e. "Welcome to GRASS 7.0.svn") to present day (SVN-trunk -> git-master) - * i.e., all 7.x and later release branches + master - * repository **grass-legacy** - * Source code from 1987 (pre-public internet times; manually reconstructed) - 2018 (r72361 - last commit to releasebranch_6_4) - * i.e., a separate repository for older GRASS GIS releases (3.2, 4.x, 5.x, 6.x) - * repository **grass-addons** - * repository for addons - * code re-organized from directory-like layout (grass6, grass7) into branches-like layout (master == grass7, grass6, ...) - * repository **grass-promo** - * repository for promotional material +* repository **grass** + * Source code from 2008 (as the starting commit r31142 was selected, i.e. "Welcome to GRASS 7.0.svn") to present day (SVN-trunk -> git-master) + * i.e., all 7.x and later release branches + master +* repository **grass-legacy** + * Source code from 1987 (pre-public internet times; manually reconstructed) - 2018 (r72361 - last commit to releasebranch_6_4) + * i.e., a separate repository for older GRASS GIS releases (3.2, 4.x, 5.x, 6.x) +* repository **grass-addons** + * repository for addons + * code re-organized from directory-like layout (grass6, grass7) into branches-like layout (master == grass7, grass6, ...) +* repository **grass-promo** + * repository for promotional material -The final destination of these repositories will be under - - https://github.com/OSGeo/ +The final destination of these repositories will be under ## Authorship and SVN user name mapping to GitHub @@ -48,12 +46,12 @@ Given GRASS GIS’ history of 35+ years we had to invest major effort in identif The following circumstances could be identified: - * user present in CVS but not in SVN - * user present in SVN but not in CVS - * user present in both with identical name - * user present in both with different name as some were changed in the CVS to SVN migration in 2007, leading to colliding user names - * some users already having a GitHub account (with mostly different name again) - * see here for the [author mapping table](https://trac.osgeo.org/grass/browser/grass-addons/tools/svn2git/) +* user present in CVS but not in SVN +* user present in SVN but not in CVS +* user present in both with identical name +* user present in both with different name as some were changed in the CVS to SVN migration in 2007, leading to colliding user names +* some users already having a GitHub account (with mostly different name again) + * see here for the [author mapping table](https://trac.osgeo.org/grass/browser/grass-addons/tools/svn2git/) **Important**: nothing is lost as contributions can be [claimed](https://help.github.com/en/articles/why-are-my-commits-linked-to-the-wrong-user) in GitHub. @@ -63,44 +61,44 @@ As the cut-off date for the trac migration we selected 2007-12-09 (r25479) as it The tickets migrated from trac to GitHub contain updated links in the ticket texts: - * links to other tickets (closed now pointing to full trac URL, open pointing to a new github issues). Note that there were many styles of referring in the commit log message which had to be parsed accordingly. - * links to trac wiki (now pointing to full trac URL) - * links source code in SVN (now pointing to full trac URL) - * images and attachments (now pointing to full trac URL) +* links to other tickets (closed now pointing to full trac URL, open pointing to a new github issues). Note that there were many styles of referring in the commit log message which had to be parsed accordingly. +* links to trac wiki (now pointing to full trac URL) +* links source code in SVN (now pointing to full trac URL) +* images and attachments (now pointing to full trac URL) Labels are preserved by transferring: - * "operating system" trac label into the GitHub issue text itself (following the new issue reporting template) - * converting milestones/tickets/comments/labels - * converting trac usernames to known GitHub usernames (those missing at time can [claim](https://help.github.com/en/articles/why-are-my-commits-linked-to-the-wrong-user) commits) - * setting assignees if possible; otherwise set new "grass-svn2git" an assignee +* "operating system" trac label into the GitHub issue text itself (following the new issue reporting template) +* converting milestones/tickets/comments/labels +* converting trac usernames to known GitHub usernames (those missing at time can [claim](https://help.github.com/en/articles/why-are-my-commits-linked-to-the-wrong-user) commits) +* setting assignees if possible; otherwise set new "grass-svn2git" an assignee **New labels in the GitHub issue tracker:** The trac component of the bug reports have been cleaned up following other OSGeo projects like GDAL and QGIS, leading to the following categories: - * **Issue category**: - * bug - * enhancement - * **Priority**: - * blocker - * critical - * feedback needed - * **Issue solution** (other than fixing and closing it normally): - * duplicate - * invalid - * wontfix - * worksforme - * **Components**: - * docs - * GUI - * libs - * modules - * packaging - * python - * translations - * unittests - * Windows specific +* **Issue category**: + * bug + * enhancement +* **Priority**: + * blocker + * critical + * feedback needed +* **Issue solution** (other than fixing and closing it normally): + * duplicate + * invalid + * wontfix + * worksforme +* **Components**: + * docs + * GUI + * libs + * modules + * packaging + * python + * translations + * unittests + * Windows specific Note that "normal" bugs reported will not carry a label in order to not overload the visual impact and readability. @@ -108,29 +106,30 @@ Note that "normal" bugs reported will not carry a label in order to not overload Before the new Git repository is open for writing, we need to have rules and best practices for dealing with the following: - * Policy for automatic merge commits due to un-synchronous nature of Git. Do we want to avoid those by `git pull --rebase`? - * How to do backports? - * A branch for every feature or bug fix in the main repo or is this done in the fork? - * _(add more)_ +* Policy for automatic merge commits due to un-synchronous nature of Git. Do we want to avoid those by `git pull --rebase`? +* How to do backports? +* A branch for every feature or bug fix in the main repo or is this done in the fork? +* _(add more)_ ## Turning SVN/trac into readonly mode -As soon as the above listed repositories are stable and functional, SVN/trac (https://trac.osgeo.org/grass/) at OSGeo will be set into readonly mode. They will serve as a reference for existing links and also for the aforementioned converted commit messages and issues in the issue tracker. +As soon as the above listed repositories are stable and functional, SVN/trac () at OSGeo will be set into readonly mode. They will serve as a reference for existing links and also for the aforementioned converted commit messages and issues in the issue tracker. ## Open issues - * Will be also Trac wiki migrated into GitHub? - * This can be decided at a later stage. Managed in [#3789](https://trac.osgeo.org/grass/ticket/3789) +* Will be also Trac wiki migrated into GitHub? + * This can be decided at a later stage. Managed in [#3789](https://trac.osgeo.org/grass/ticket/3789) ## Mirror or Exit strategy GitHub is a closed platform. In case it would be shutdown, closed or GitHub would start asking unreasonable fees, a backup strategy is needed. The proposed solution is - * GitLab has an import module from GitHub. - * implement a continuous mirror on GitLab.com including the issues and wiki. - * OSGeo-gitea code mirror: https://git.osgeo.org/gitea/grass_gis/grass - * See https://docs.gitlab.com/ee/workflow/repository_mirroring.html - * The mirroring is only for the repository, not the issues or wiki. + +* GitLab has an import module from GitHub. + * implement a continuous mirror on GitLab.com including the issues and wiki. + * OSGeo-gitea code mirror: + * See + * The mirroring is only for the repository, not the issues or wiki. diff --git a/doc/howto_release.md b/doc/howto_release.md index 744b7719239..f343601e508 100644 --- a/doc/howto_release.md +++ b/doc/howto_release.md @@ -204,7 +204,7 @@ Older release description may or may not be a good inspiration: If RC, mark it as a pre-release, check: -``` +```text [x] This is a pre-release ``` @@ -291,7 +291,7 @@ md5sum grass-${VERSION}.tar.gz > grass-${VERSION}.md5sum ### Upload source code tarball to OSGeo servers Note: servers 'osgeo8-grass' and 'osgeo7-download' only reachable via - jumphost (managed by OSGeo-SAC) - see https://wiki.osgeo.org/wiki/SAC_Service_Status#grass + jumphost (managed by OSGeo-SAC) - see ```bash # Store the source tarball (twice) in (use scp -p FILES grass:): @@ -336,8 +336,8 @@ vim wingrass-maintenance-scripts/cronjob.sh # major/minor release only Add the new version to repos which build or test addons: -- https://github.com/OSGeo/grass-addons/blob/grass8/.github/workflows/ci.yml (currently, for new branches only) -- https://github.com/landam/wingrass-maintenance-scripts/blob/master/grass_addons.sh (add new release related line for new branches and final releases) +- (currently, for new branches only) +- (add new release related line for new branches and final releases) ## Close milestone @@ -366,19 +366,19 @@ are any which show well specific features added or updated in the release. ### Trac Wiki release page -Add entry in https://trac.osgeo.org/grass/wiki/Release +Add entry in ### Update Hugo web site to show new version For a (final) release (not release candidate), write announcement and publish it: -- News section, https://github.com/OSGeo/grass-website/tree/master/content/news +- News section, Software pages: -- Linux: https://github.com/OSGeo/grass-website/blob/master/content/download/linux.en.md -- Windows: https://github.com/OSGeo/grass-website/blob/master/content/download/windows.en.md -- Mac: https://github.com/OSGeo/grass-website/blob/master/content/download/mac.en.md -- Releases: https://github.com/OSGeo/grass-website/blob/master/content/about/history/releases.md -- Wiki: https://grasswiki.osgeo.org/wiki/GRASS-Wiki +- Linux: +- Windows: +- Mac: +- Releases: +- Wiki: ### Only in case of new major release @@ -386,10 +386,10 @@ Software pages: - update cronjob '[cron_grass8_main_src_snapshot.sh](https://github.com/OSGeo/grass-addons/tree/grass8/utils/cronjobs_osgeo_lxd/)' on grass.osgeo.org to next but one release tag for the differences - wiki updates, only when new major release: - - {{cmd|xxxx}} macro: - - update last version on main page + - {{cmd|xxxx}} macro: + - update last version on main page - Add trac Wiki Macro definitions for manual pages G8X:modulename - - Edit: + - Edit: ## Packaging notes @@ -397,7 +397,7 @@ Software pages: - Update grass_packager_release.bat, eg. -``` +```bash set MAJOR=8 set MINOR=2 set PATCH=0RC1 @@ -405,13 +405,13 @@ Software pages: - Update addons (grass_addons.sh) rules, eg. -``` +```bash compile $GIT_PATH/grass8 $GISBASE_PATH/grass820RC1 $ADDON_PATH/grass820RC1/addons ``` - Modify grass_copy_wwwroot.sh accordingly, eg. -``` +```bash copy_addon 820RC1 8.2.0RC1 ``` @@ -423,22 +423,22 @@ Software pages: ### Other notes - - - - - + - + - ## Tell others about release - If release candidate: - - - - + - + - - If official release: - - publish related announcement press release at: + - publish related announcement press release at: - Our GRASS web site: /announces/ - - Note: DON'T use relative links there + - Note: DON'T use relative links there - Our main mailing lists: - - | - - | - - | + - | + - | + - | - FreeGIS: - OSGeo.org: , diff --git a/doc/infrastructure.md b/doc/infrastructure.md index 07910485617..5cdc36a4011 100644 --- a/doc/infrastructure.md +++ b/doc/infrastructure.md @@ -5,41 +5,41 @@ Last changed: July 2020 Related Wiki documents: -* https://grass.osgeo.org/wiki/GRASS_Migration_to_OSGeo (historical document) +* (historical document) ## GRASS GIS Source code repository -Maintainer: Markus Neteler, Martin Landa, OSGeo-SAC, http://wiki.osgeo.org/wiki/SAC +Maintainer: Markus Neteler, Martin Landa, OSGeo-SAC, Important update April 2019: The source code is now managed on GitHub (rather than in SVN). The GitHub repositories are: -* GRASS GIS core (7.x): https://github.com/OSGeo/grass -* GRASS GIS legacy (3.x-6.x): https://github.com/OSGeo/grass-legacy -* GRASS GIS Add-ons: https://github.com/OSGeo/grass-addons -* GRASS GIS promotional material: https://github.com/OSGeo/grass-promo -* GRASS GIS Website (hugo site): https://github.com/OSGeo/grass-website -* Github mirror at OSGeo: https://git.osgeo.org/gitea/grass_gis/grass +* GRASS GIS core (7.x): +* GRASS GIS legacy (3.x-6.x): +* GRASS GIS Add-ons: +* GRASS GIS promotional material: +* GRASS GIS Website (hugo site): +* Github mirror at OSGeo: Git usage: * [CONTRIBUTING.md file](../CONTRIBUTING.md) -* https://trac.osgeo.org/grass/wiki/HowToGit +* Issues: -* https://github.com/OSGeo/grass/issues -* old trac instance: https://trac.osgeo.org/grass +* +* old trac instance: Trac related notes: * For easier linking in the Trac Wiki, some macro definitions are used for manual page refs (G7:modulename) - * https://trac.osgeo.org/grass/wiki/InterMapTxt + * * ZIP file download support in trac (was needed for g.extension) * on trac.osgeo.org: -``` +```text /var/www/trac/grass/conf/trac.ini [browser] downloadable_paths = /grass-addons/grass7/*/*,/sandbox/*/* @@ -47,78 +47,78 @@ downloadable_paths = /grass-addons/grass7/*/*,/sandbox/*/* Statistics: -* https://github.com/OSGeo/grass/pulse -* https://trac.osgeo.org/grass/stats/code +* +* ## GRASS Web server Maintainer: M. Neteler -* https://grass.osgeo.org - * osgeo8-grass: LXD container on osgeo8 (https://wiki.osgeo.org/wiki/SAC_Service_Status#osgeo_8) - * OS: Debian Buster - * Apache Server with hugo (https://github.com/OSGeo/grass-website) - * for migration details (7/2020), see https://github.com/OSGeo/grass-website/issues/180 - * ssh login: via jumphost hop.osgeo8.osgeo.org - * deployment via cronjob: https://github.com/OSGeo/grass-addons/tree/grass8/utils/cronjobs_osgeo_lxd/ -* https://old.grass.osgeo.org (CMSMS, replaced in 2020 by above hugo based solution) - * Shared virtual OSGeo machine (osgeo6) hosted at Oregon State University Open Source Lab - (server: osgeo6.osgeo.osuosl.org) - * Login: via OSGeo LDAP, there is a "grass" LDAP group - * Software: - * OS: Debian Wheezy - * Apache Server with PHP - * Login: via OSGeo LDAP, there is a "grass" LDAP group +* + * osgeo8-grass: LXD container on osgeo8 () + * OS: Debian Buster + * Apache Server with hugo () + * for migration details (7/2020), see + * ssh login: via jumphost hop.osgeo8.osgeo.org + * deployment via cronjob: +* (CMSMS, replaced in 2020 by above hugo based solution) + * Shared virtual OSGeo machine (osgeo6) hosted at Oregon State University Open Source Lab + server: osgeo6.osgeo.osuosl.org) + * Login: via OSGeo LDAP, there is a "grass" LDAP group + * Software: + * OS: Debian Wheezy + * Apache Server with PHP + * Login: via OSGeo LDAP, there is a "grass" LDAP group * Backups: - * osgeo8-grass: container on osgeo8 is backup'ed, see http://wiki.osgeo.org/wiki/SAC:Backups + * osgeo8-grass: container on osgeo8 is backup'ed, see * Mirrors: - * rsync, see https://grass.osgeo.org/contribute/ --> Mirror - * mirror list, see https://grass.osgeo.org/about/mirrors/ -* RSS feed: offered by hugo at https://grass.osgeo.org/index.xml, used at https://planet.osgeo.org + * rsync, see --> Mirror + * mirror list, see +* RSS feed: offered by hugo at , used at * Weekly software snapshots (generated Saturday morning Portland (OR), US time): - * Source code tarball of git (GitHub) https://github.com/OSGeo/grass - * Linux binary snapshot is compiled on osgeo8-grass - * GRASS is compiled with GDAL, PROJ, SQLite, MySQL, PostgreSQL, FFTW, C++ support - * binary tar.gz and manuals are moved into Web space + * Source code tarball of git (GitHub) + * Linux binary snapshot is compiled on osgeo8-grass + * GRASS is compiled with GDAL, PROJ, SQLite, MySQL, PostgreSQL, FFTW, C++ support + * binary tar.gz and manuals are moved into Web space * GRASS user manual HTML: - * generated during compilation of weekly Linux binary snapshot on osgeo8-grass + * generated during compilation of weekly Linux binary snapshot on osgeo8-grass * GRASS addons manual HTML: - * generated during compilation of weekly Linux binary snapshot on osgeo8-grass + * generated during compilation of weekly Linux binary snapshot on osgeo8-grass -* GRASS programmer's manual (https://grass.osgeo.org/programming8/) - * HTML: cronjob run Wednesday morning Portland (OR), US time - * HTML: cronjob run Saturday morning Portland (OR), US time - * disabled: PDF: cronjob run Saturday morning Portland (OR), US time +* GRASS programmer's manual () + * HTML: cronjob run Wednesday morning Portland (OR), US time + * HTML: cronjob run Saturday morning Portland (OR), US time + * disabled: PDF: cronjob run Saturday morning Portland (OR), US time -* i18N translation statistics (https://grass.osgeo.org/development/translations/#statistics) - * generated during compilation of Linux binary snapshot, stats of `(cd locale; make)` are extracted into text file - * text file parsed by PHP page and shown as table - * GRASS GIS version is coded in devel/i18n_stats.inc - * for Transifex integration, see below +* i18N translation statistics () + * generated during compilation of Linux binary snapshot, stats of `(cd locale; make)` are extracted into text file + * text file parsed by PHP page and shown as table + * GRASS GIS version is coded in devel/i18n_stats.inc + * for Transifex integration, see below * Mailman mailing lists + greylisting (at lists.osgeo.org since 11/2007) - * Mailman is doing the job, only registered users can post - * messages from unsubscribed people is auto-discarded without notification - * the open "weblist" operates instead like this: - * User -> grass-web at lists osgeo.org -> greylisting -> Mailman + * Mailman is doing the job, only registered users can post + * messages from unsubscribed people is auto-discarded without notification + * the open "weblist" operates instead like this: + * User -> grass-web at lists osgeo.org -> greylisting -> Mailman * Backup of mailing lists (mbox files) - * nightly backup at OSGeo.org, bacula + * nightly backup at OSGeo.org, bacula * Web statistics - * See URL at http://wiki.osgeo.org/wiki/Project_Stats - * cronjob script: /osgeo/scripts/update_logs.sh + * See URL at + * cronjob script: /osgeo/scripts/update_logs.sh Summary: The system should run almost autonomously. ## WinGRASS maintenance scripts -* https://github.com/landam/wingrass-maintenance-scripts +* ## GRASS Mailing lists @@ -127,31 +127,31 @@ Maintainer: Markus Neteler Available lists: -* at OSGeo.org (https://lists.osgeo.org/mailman/listinfo): - grass-abm Integration of GRASS with JAVA based agent based modeling (ABM) +* at OSGeo.org (): + grass-abm Integration of GRASS with JAVA based agent based modeling (ABM) grass-announce GRASS announcements - grass-commit Mailing list to distribute GRASS-CVS commits - grass-dev GRASS GIS Development mailing list - grass-es La lista de correo de GRASS GIS en español - grass-psc GRASS-PSC: GRASS Project Steering Committee - grass-stats GRASS and statistical software - grass-translations Translation of GRASS (i18N) - grass-user GRASS user list - grass-web GRASS website mailing list - -* OLD, UNUSED: at FBK-irst (http://grass.fbk.eu/mailman/admin/): + grass-commit Mailing list to distribute GRASS-CVS commits + grass-dev GRASS GIS Development mailing list + grass-es La lista de correo de GRASS GIS en español + grass-psc GRASS-PSC: GRASS Project Steering Committee + grass-stats GRASS and statistical software + grass-translations Translation of GRASS (i18N) + grass-user GRASS user list + grass-web GRASS website mailing list + +* OLD, UNUSED: at FBK-irst (): grass-commit-addons Mailing list to distribute GRASS Addons-SVN commits - grass-gui GRASSGUI mailing list - grass-qa GRASS Quality Assessment and monitoring list - grass-windows winGRASS * Using GRASS on MS-Windows systems mailing list + grass-gui GRASSGUI mailing list + grass-qa GRASS Quality Assessment and monitoring list + grass-windows winGRASS * Using GRASS on MS-Windows systems mailing list Notes: * grass-announce: - * moderated by M. Neteler - * has monthly password reminder disabled to avoid leakage into publicly archived lists + * moderated by M. Neteler + * has monthly password reminder disabled to avoid leakage into publicly archived lists * grass-commit is receiving posts from the GRASS SVN at osgeo.org. Not open for other postings, they will be trashed automatically * grass-web is an open list (posting without subscription possible) with (Google) spam filter - * moderated by M. Neteler to avoid spam + * moderated by M. Neteler to avoid spam * OLD, UNUSED: grass-qa is receiving posts from the GRASS Quality Control System at Ecole Polytechnique de Montreal, Canada. Not open for other postings. @@ -159,7 +159,7 @@ Notes: Maintainer: Martin Landa, Markus Neteler -* https://grasswiki.osgeo.org +* * Mediawiki * mirrored at CZ Tech University * requires registration to keep spammers out @@ -167,58 +167,62 @@ Maintainer: Martin Landa, Markus Neteler Summary: The system should run almost autonomous. An eye must be be kept on people trying to spam the site Macros for manual pages (src, cmd, API, ...): -* https://grasswiki.osgeo.org/wiki/Category:Templates +* ## GRASS IRC Channel: irc://irc.freenode.net/grass -Web based client: See https://grasswiki.osgeo.org/wiki/IRC +Web based client: See * channel owner: Alessandro Frigeri ("geoalf") * quasi guru level: Markus Neteler ("markusN") * further operators: - * Jachym ("jachym") - * Luca ("doktoreas") - * Soeren ("huhabla") - * Brad ("bdouglas") + * Jachym ("jachym") + * Luca ("doktoreas") + * Soeren ("huhabla") + * Brad ("bdouglas") ## GRASS Bugtracker Current bugtracker (Jan 2020 - today): - * https://github.com/OSGeo/grass/issues + +* Old bugtracker (Jan 2008 - Jan 2020): - * https://trac.osgeo.org/grass/report - * posted new bugs and comments to grass-dev list - * Settings: + +* +* posted new bugs and comments to grass-dev list +* Settings: Old tracsvn (OSGeo server) (Dec 2007 * Mai 2019) -``` +```text /var/www/trac/env/grass/conf/trac.ini downloadable_paths = /grass-addons/grass7/*/*,/sandbox/*/* path = /var/www/grass/htdocs - link = https://grass.osgeo.org/ + link = src = site/grasslogo_vector_small.png smtp_always_cc = grass-dev@lists.osgeo.org smtp_replyto = grass-dev@lists.osgeo.org - url = https://grass.osgeo.org + url = .dir = /var/www/svn/repos/grass - base_url = https://trac.osgeo.org/grass/ + base_url = database = postgres://postgres@/trac_grass ``` Very old bugtracker (Jan 2007 * Dec 2008): - * http://wald.intevation.org/tracker/?group_id=21 - * gforce, sponsored by Intevation GmbH, Germany - * spamassasin spamfilter locally, bogofilter at grass-dev list - * needs 'noreply*wald.intevation.org' to be enabled as alias in Mailman + +* +* gforce, sponsored by Intevation GmbH, Germany +* spamassasin spamfilter locally, bogofilter at grass-dev list +* needs `noreply*wald.intevation.org` to be enabled as alias in Mailman Very very old bugtracker (Dec 2000 * Dec 2006): - * https://intevation.de/rt/webrt?q_queue=grass - * webRT, sponsored by Intevation GmbH, Germany - * spamassasin spamfilter locally, bogofilter at grass-dev list - * reports are directly sent to GRASS Developers mailing list for notification - * TODO: migrate to trac + +* +* webRT, sponsored by Intevation GmbH, Germany +* spamassasin spamfilter locally, bogofilter at grass-dev list +* reports are directly sent to GRASS Developers mailing list for notification +* TODO: migrate to trac ## GRASS Addons @@ -227,9 +231,9 @@ Maintainer: Martin Landa and Markus Neteler Details: -- Windows-addons: grass-addons/utils/addons/README.txt -- Addon manual pages cronjob: https://github.com/OSGeo/grass-addons/tree/master/utils/cronjobs_osgeo_lxd -- Rendered manuals: https://grass.osgeo.org/grass8/manuals/addons/ +* Windows-addons: grass-addons/utils/addons/README.txt +* Addon manual pages cronjob: +* Rendered manuals: The redirect to the latest grass7x directory is defined on grass.osgeo.org: /etc/apache2/includes/grass.osgeo.org.inc @@ -238,26 +242,26 @@ Procedure building of binaries (Windows): * Addons module are compiled on build server, currently at the CTU in Prague) and publishing their manual pages on publishing server, i.e. grass.osgeo.org. * A new compilation is triggered everytime when a commit is done in the Addons-SVN. * Logs: - * Linux log files: https://grass.osgeo.org/addons/grass7/logs (compiled on `grasslxd` on `osgeo7`) - * Windows log files: http://wingrass.fsv.cvut.cz/grass78/x86_64/addons/latest/logs/ + * Linux log files: (compiled on `grasslxd` on `osgeo7`) + * Windows log files: Procedure of granting write access to Addons repo: -* Request procedure: https://trac.osgeo.org/grass/wiki/HowToContribute#WriteaccesstotheGRASS-Addons-SVNrepository -* Adding OSGeo-ID: https://www.osgeo.org/cgi-bin/auth/ldap_group.py?group=grass_addons -* Adding contributor: https://trac.osgeo.org/grass/browser/grass-addons/contributors.csv (via SVN commit) +* Request procedure: +* Adding OSGeo-ID: +* Adding contributor: (via SVN commit) * Confirm request in grass-psc and give instructions concerning code style etc (see archive for examples) -XML file for g.extension: https://grass.osgeo.org/addons/grass7/modules.xml +XML file for g.extension: * generated in grass-addons/utils/addons/grass-addons-publish.sh ## GRASS Travis CI Maintainer: Martin Landa -* https://travis-ci.org/GRASS-GIS -* https://github.com/OSGeo/grass -* OLD: https://github.com/GRASS-GIS/grass-ci -* https://github.com/OSGeo/grass-addons/tree/master/utils/grass-ci/ +* +* +* OLD: +* Travis CI control files: trunk/.travis/ @@ -266,7 +270,7 @@ Travis CI control files: linux.script.sh Maintenance script: -* https://github.com/OSGeo/grass-addons/tree/master/utils/grass-ci/grass-ci.sh +* The github update is run as a cronjob on server "geo102" (CTU, CZ). @@ -277,15 +281,15 @@ Started Apr. 2020 Maintainer: Vaclav Petras -* https://github.com/OSGeo/grass/actions -* Details: https://github.com/OSGeo/grass/pull/525 +* +* Details: * CI workflow with: - * A build job which is not parallelized and is meant for clear & relatively fast check of compilation and building in general. (Duplicating what is running on Travis) - * A test job which of course needs to build, but the main focus is to run tests, so the compilation is parallelized (depending on nproc) and thus potentially less readable. This runs the whole test suite. (You need to run it locally to see the actual error, but you can see which tests are failing.) + * A build job which is not parallelized and is meant for clear & relatively fast check of compilation and building in general. (Duplicating what is running on Travis) + * A test job which of course needs to build, but the main focus is to run tests, so the compilation is parallelized (depending on nproc) and thus potentially less readable. This runs the whole test suite. (You need to run it locally to see the actual error, but you can see which tests are failing.) * Static code analysis/Code quality check using Flake8 with separate checks for python/grass, gui/wxpython, scripts and temporal directories. - * Configurations ignore different lists of Flake8 errors. The idea is to reduce that to minimum. - * Code in testsuite directories is also ignored for now, but should not be in the future. + * Configurations ignore different lists of Flake8 errors. The idea is to reduce that to minimum. + * Code in testsuite directories is also ignored for now, but should not be in the future. Helper files placed to .github/workflows @@ -294,19 +298,19 @@ Helper files placed to .github/workflows Maintainer: Markus Neteler -* https://scan.coverity.com/projects/grass?tab=overview +* ## Transifex translation management i18N gettext messages: -* Dashboard: https://www.transifex.com/grass-gis/ +* Dashboard: * Auto-update URL to fetch files: - * https://www.transifex.com/grass-gis/grass7/content/ - * Menu: Resources - * Use: "Auto update resources" button -* Weblate: https://weblate.osgeo.org/ + * + * Menu: Resources + * Use: "Auto update resources" button +* Weblate: ## OLD: GRASS Quality Control @@ -314,13 +318,14 @@ i18N gettext messages: Maintainer: Prof. Giulio Antoniol * offline. -* http://web.soccerlab.polymtl.ca/grass-evolution/grass-browsers/grass-index-en.html +* was implemented and sponsored by Ecole Polytechnique de Montreal, Canada -* Realtime analysis has been sent to: http://lists.osgeo.org/mailman/listinfo/grass-qa +* Realtime analysis has been sent to: Further notification/functionality test systems: - * posts into #grass IRC channel - * posts into #osgeo-commits IRC channel + +* posts into #grass IRC channel +* posts into #osgeo-commits IRC channel ## Previous hosting sponsors diff --git a/doc/notebooks/README.md b/doc/notebooks/README.md index 99e731da877..51d764e8474 100644 --- a/doc/notebooks/README.md +++ b/doc/notebooks/README.md @@ -1,3 +1,5 @@ +# Notebooks + ## Introduction ### Using the notebooks locally @@ -13,14 +15,14 @@ See also the official documentation for [The Jupyter Notebook](https://jupyter-n ### Introductory notebooks to GRASS GIS and Jupyter - - GRASS GIS in Jupyter Notebook with Python and grass.jupyter: [jupyter_example.ipynb](jupyter_example.ipynb) - - The grass.jupyter Package: [jupyter_tutorial.ipynb](jupyter_tutorial.ipynb) +* GRASS GIS in Jupyter Notebook with Python and grass.jupyter: [jupyter_example.ipynb](jupyter_example.ipynb) +* The grass.jupyter Package: [jupyter_tutorial.ipynb](jupyter_tutorial.ipynb) -## Thematic Jupyter notebooks: +## Thematic Jupyter notebooks - - Viewshed Analysis: [viewshed_analysis.ipynb](viewshed_analysis.ipynb) - - Spatio-Temporal Analysis with grass.jupyter: [temporal.ipynb](temporal.ipynb) - - Solar Energy Potential Analysis: [solar_potential.ipynb](solar_potential.ipynb) - - GRASS GIS Scripting with Python: [scripting_example.ipynb](scripting_example.ipynb) - - Hydrology with GRASS GIS: [hydrology.ipynb](hydrology.ipynb) +* Viewshed Analysis: [viewshed_analysis.ipynb](viewshed_analysis.ipynb) +* Spatio-Temporal Analysis with grass.jupyter: [temporal.ipynb](temporal.ipynb) +* Solar Energy Potential Analysis: [solar_potential.ipynb](solar_potential.ipynb) +* GRASS GIS Scripting with Python: [scripting_example.ipynb](scripting_example.ipynb) +* Hydrology with GRASS GIS: [hydrology.ipynb](hydrology.ipynb) diff --git a/docker/README.md b/docker/README.md index 5dcc11e18a9..d94b08874b1 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,6 +1,8 @@ -[![Docker Pulls](https://img.shields.io/docker/pulls/mundialis/grass-py3-pdal.svg)](https://grass.osgeo.org/download/software/docker-images/) +# GRASS GIS docker + +## GRASS GIS docker matrix -# GRASS GIS docker matrix +[![Docker Pulls](https://img.shields.io/docker/pulls/mundialis/grass-py3-pdal.svg)](https://grass.osgeo.org/download/software/docker-images/) | Base image | Docker tag | GRASS GIS | PROJ | GDAL | PDAL | Python | Image size | |--------------|-----------------|------------|-------|-------|-------|--------|------------| @@ -12,18 +14,18 @@ | Debian 10.1 | stable-debian | 8.2 branch | 5.2.0 | 2.4.0 | 1.8.0 | 3.7.3 | 1.16 GB | | Alpine 3.12 | stable-alpine | 8.2 branch | 7.0.1 | 3.1.4 | 2.1.0 | 3.8.10 | 186 MB | -Last update: 27 Apr 2022 (source: https://github.com/OSGeo/grass/actions/workflows/docker.yml and https://hub.docker.com/r/mundialis/grass-py3-pdal/tags) +Last update: 27 Apr 2022 (source: and ) -# Requirements +## Requirements - * docker or podman +* docker or podman -# Installation +## Installation To install a docker image, run (replace `` with the desired Docker tag from the table above): -``` +```bash docker pull mundialis/grass-py3-pdal: ``` -See also: https://grass.osgeo.org/download/docker/ +See also: diff --git a/docker/testdata/README.md b/docker/testdata/README.md index 1b9e9dca3ea..100c1b7926b 100644 --- a/docker/testdata/README.md +++ b/docker/testdata/README.md @@ -1 +1,3 @@ +# Test data + Data source: diff --git a/macosx/ReadMe.md b/macosx/ReadMe.md index 2a71608c552..e6cd9bbb72c 100644 --- a/macosx/ReadMe.md +++ b/macosx/ReadMe.md @@ -1,28 +1,28 @@ -| :exclamation: Instructions below are not up-to-date. Update in progress. | -|---------------------------------------------------------------------------| - # GRASS GIS Mac OS X Build (and other Mac notes) ## Table of Contents +| :exclamation: Instructions below are not up-to-date. Update in progress. | +|---------------------------------------------------------------------------| + - Quickstart - About - Building GRASS - - Optimization - - Configure Example - - Leopard Notes - - Building an Installer Package - - Bundling Libraries and Programs + - Optimization + - Configure Example + - Leopard Notes + - Building an Installer Package + - Bundling Libraries and Programs - Developer Notes - Help Files - Addon Modules - Dependency Build Notes - - Universal Aqua Tcl/Tk - - Universal GPSBabel - - Universal NetPBM - - Universal FFMPEG + - Universal Aqua Tcl/Tk + - Universal GPSBabel + - Universal NetPBM + - Universal FFMPEG ## Quickstart @@ -170,7 +170,7 @@ As an example, to build GRASS using my frameworks and Tcl/Tk as built in the build notes below, this should work *(for a standard unix build, just remove the `--prefix` and `--enable-macosx-app` flags)*: -```sh +```bash ./configure \ --with-freetype \ --with-freetype-includes= \ @@ -233,7 +233,7 @@ and [gui/wxpython/README](../gui/wxpython/README), wxpython installer available at [wxpython.org](http://wxpython.org/)), add this to configure (fill in the correct version at x.x.x.x for the wxpython you have installed): -``` +```bash --with-python --with-wxwidgets=/usr/local/lib/wxPython-unicode-x.x.x.x/bin/wx-config ``` @@ -243,7 +243,7 @@ system Python on Leopard. If you want ffmpeg support (see build instructions below), add this: -```sh +```bash --with-ffmpeg \ --with-ffmpeg-includes="/usr/local/include \ /usr/local/include/libavcodec /usr/local/include/libavdevice \ @@ -255,7 +255,7 @@ If you want ffmpeg support (see build instructions below), add this: For cairo support (see build instructions at [kyngchaos.com](https://web.archive.org/web/20161112052733/http://www.kyngchaos.com/macosx/build/cairo/)), add this: -```sh +```bash --with-cairo \ --with-cairo-includes=/usr/local/include/cairo \ --with-cairo-libs=/usr/local/lib \ @@ -390,7 +390,7 @@ folder in a Terminal and: `Platform [darwin] ==>` ↵ -`Netpbm shared library directory [default] ==> `**`/usr/local`** +`Netpbm shared library directory [default] ==>` **`/usr/local`** choose where you will install it default is NOT /usr/local or any location at all, so you MUST set this @@ -652,4 +652,4 @@ This program is free software under the GNU General Public License (>=v2). kyngchaos@kyngchaos.com -http://www.kyngchaos.com/ + diff --git a/mswindows/external/rbatch/batchfiles.md b/mswindows/external/rbatch/batchfiles.md index b3908665a66..d4f738972c7 100644 --- a/mswindows/external/rbatch/batchfiles.md +++ b/mswindows/external/rbatch/batchfiles.md @@ -68,7 +68,7 @@ Typical usage of `R.bat` to launch R gui is the following ^[ If `R.exe` were on the Windows path and before `R.bat` then it would have to be written as follows: `R.bat gui`]: -``` +```bash R gui ``` @@ -96,7 +96,7 @@ remainder becomes the default subcommand. For example, if `R.bat` were renamed Other executable files that come with R (`R.exe`, `Rcmd.exe`, `Rscript.exe`) can be run in a similar way: -``` +```bash R --help R cmd --help R script --help @@ -109,7 +109,7 @@ discussed later.) There are also some support commands: -``` +```bash R cd R dir R ls @@ -128,7 +128,7 @@ Below is a list with typical values. These values are determined by the script heuristically (or the user can set any before running `R.bat` or `R.bat` itself can be customized by setting any of them near top of the script). -``` +```text R_ARCH=x64 R_CMD=RShow R_HOME=C:\Program Files\R\R-2.15.3 @@ -161,7 +161,7 @@ values for these variables. The command -``` +```bash R path ``` @@ -178,7 +178,7 @@ since `R.bat` will not have to run each time that `R` is started. ^[On a Note that if both `R.bat` and `R.exe` exist on the Windows path then the first on the path will be called if one uses: -``` +```bash R ...arguments... ``` @@ -192,7 +192,7 @@ described later.) The command -``` +```bash R tools ``` @@ -210,7 +210,7 @@ installation in `R_ROOT` which has the most recent date will be used. If we enter this at the `cmd` line: -``` +```bash set R_VER=R-2.14.0 ``` @@ -218,7 +218,7 @@ then for the remainder of this `cmd` line session that version will be used. If one wishes to use two different R versions at once we could spawn a new `cmd` line session: -``` +```bash start ``` @@ -229,7 +229,7 @@ window it will use the specified version. One can change the registry entry permanently to refer to a particlar version like this: -``` +```bash cmd /c set R_VER=R-2.14.0 ^& R SetReg ``` @@ -242,7 +242,7 @@ determined by which R install directory is the most recent. To make a particular R install directory the most recent run the following in a `cmd` line session with Administrator privileges: -``` +```bash R dir el cmd /c set R_VER=R-2.14.0 ^& R touch ``` @@ -307,14 +307,14 @@ be ignored since it would be regarded as a comment by R.) For example, if we have a file `test.bat` with the following two lines: -``` +```R #Rscript %0 %* print(pi) ``` then we can invoke it from the Windows cmd line like this: -``` +```bash test ``` @@ -338,7 +338,7 @@ There is more information on this in the comments at the top of the script. The command -``` +```bash Rpathset ``` @@ -350,7 +350,7 @@ the R binaries will be on the path so they can be accessed directly without `Rpathset` is an alternative to -``` +```bash R path ``` @@ -366,7 +366,7 @@ work on untested Windows configurations. `Rpathset.bat` might be used like this: -``` +```bash Rpathset Rgui ``` @@ -384,7 +384,7 @@ another. If used to transfer packages from one version of R to another it is recommended that the user run `upgrade.packages()` in the target. For example, assuming the default location for the user libraries: -``` +```bash cd %userprofile%\Documents\win-library copydir 2.15\library 3.0\library @@ -405,7 +405,7 @@ overwrite such packages delete them from the target first using the Windows `el.js` runs its arguments elevated (i.e. with Administrator privileges). For example, -``` +```bash el R touch ``` @@ -430,6 +430,6 @@ This batch file creates a pdf of this documentation from the markdown file found [here](https://code.google.com/p/pandoc/downloads/list). It is run without arguments: -``` +```bash make-batchfiles-pdf ``` diff --git a/python/grass/gunittest/README.md b/python/grass/gunittest/README.md index 8c6111ea0e8..2a60d84be82 100644 --- a/python/grass/gunittest/README.md +++ b/python/grass/gunittest/README.md @@ -1,5 +1,5 @@ -## Testing GRASS GIS source code and modules +# Testing GRASS GIS source code and modules For more information on the test suite and unit tests, visit: -https://grass.osgeo.org/grass-devel/manuals/libpython/gunittest_testing.html + diff --git a/python/libgrass_interface_generator/README.md b/python/libgrass_interface_generator/README.md index a29324ca90a..857c436d237 100644 --- a/python/libgrass_interface_generator/README.md +++ b/python/libgrass_interface_generator/README.md @@ -1,7 +1,9 @@ +# librass interface generator + ## Notes on ctypesgen Currently installed version: -https://github.com/ctypesgen/ctypesgen/commit/fd495e5edb2f69e5407774f8937a1d62cd33fe55 (17 February 2022) + (17 February 2022) ### How to update ctypesgen version @@ -33,18 +35,18 @@ struct timespec { is not supported by Ctypes. Ctypesgen generates this code to: ```py -struct_timespec._fields_ = [ - ('tv_sec', time_t), +struct_timespec._fields_ = [ + ('tv_sec', time_t), ('unnamed_1', c_int, ((8 * (sizeof(time_t) - sizeof(c_long))) * (1234 == 4321))), - ('tv_nsec', c_long), + ('tv_nsec', c_long), ('unnamed_2', c_int, ((8 * (sizeof(time_t) - sizeof(c_long))) * (1234 != 4321))), -] +] ``` which therefore causes `ValueError: number of bits invalid for bit field` (if the bit size expression equals 0). -Reported with: https://github.com/OSGeo/grass/pull/2073 +Reported with: This patch removes the zero bit sized unnamed structure members from the generated files. @@ -53,23 +55,23 @@ generated files. --- ctypesgen/printer_python/printer.py.orig +++ ctypesgen/printer_python/printer.py @@ -22,6 +22,7 @@ class WrapperPrinter: - + self.file = open(outpath, "w") if outpath else sys.stdout self.options = options + self.has_unnamed_struct_member = False - + if self.options.strip_build_path and self.options.strip_build_path[-1] != os.path.sep: self.options.strip_build_path += os.path.sep @@ -61,9 +62,14 @@ class WrapperPrinter: self.print_group(self.options.inserted_files, "inserted files", self.insert_file) self.strip_prefixes() - + - def __del__(self): + if self.has_unnamed_struct_member and outpath: + self._add_remove_zero_bitfields() + self.file.close() - + + if self.has_unnamed_struct_member and outpath and sys.executable: + os.system("{0} {1}".format(sys.executable, outpath)) + @@ -85,7 +87,7 @@ generated files. n += 1 if name not in names: @@ -266,7 +273,10 @@ class WrapperPrinter: - + self.file.write("%s_%s.__slots__ = [\n" % (struct.variety, struct.tag)) for name, ctype in struct.members: - self.file.write(" '%s',\n" % name) @@ -94,7 +96,7 @@ generated files. + ) + self.file.write(" {0}'{1}',\n".format(skip_unnamed, name)) self.file.write("]\n") - + if len(unnamed_fields) > 0: @@ -278,9 +288,15 @@ class WrapperPrinter: self.file.write("%s_%s._fields_ = [\n" % (struct.variety, struct.tag)) @@ -116,7 +118,7 @@ generated files. self.file.write(" ('%s', %s),\n" % (name, ctype.py_string())) @@ -481,3 +497,57 @@ class WrapperPrinter: ) - + inserted_file.close() + + def _add_remove_zero_bitfields(self): @@ -178,15 +180,15 @@ generated files. #### Windows specific patches Patch for OSGeo4W packaging, adapted from -https://github.com/jef-n/OSGeo4W/blob/master/src/grass/osgeo4w/patch + ```diff --- ctypesgen/libraryloader.py.orig +++ ctypesgen/libraryloader.py @@ -372,6 +372,12 @@ class WindowsLibraryLoader(LibraryLoader): - + name_formats = ["%s.dll", "lib%s.dll", "%slib.dll", "%s"] - + + def __init__(self): + super().__init__() + for p in os.getenv("PATH").split(";"): @@ -199,17 +201,17 @@ https://github.com/jef-n/OSGeo4W/blob/master/src/grass/osgeo4w/patch ``` Invoke preprocessor via `sh.exe`, workaround to get the -I switches to be recognized. -https://trac.osgeo.org/grass/ticket/1125#comment:21 + -https://github.com/OSGeo/grass/commit/65eef4767aa416ca55f7e36f62dce7ce083fe450 + ```diff --- ctypesgen/parser/preprocessor.py.orig +++ ctypesgen/parser/preprocessor.py @@ -125,6 +125,9 @@ class PreprocessorParser(object): - + self.cparser.handle_status(cmd) - + + if IS_WINDOWS: + cmd = ["sh.exe", "-c", cmd] + diff --git a/testsuite/README.md b/testsuite/README.md index b4eec6d569a..2d4e1cfd129 100644 --- a/testsuite/README.md +++ b/testsuite/README.md @@ -1,12 +1,14 @@ +# Test suite + This directory contains scripts to check some functionality of GRASS GIS. -GRASS GIS testsuite documentation: https://grass.osgeo.org/grass-devel/manuals/libpython/gunittest_testing.html +GRASS GIS testsuite documentation: ## Simple test data Some tests may be launched in the location `../demolocation/`: -``` +```bash # create new mapset for test grass ../demolocation/user1 -c # run the test @@ -16,13 +18,13 @@ make ## Extended test data Most tests require the North Carolina Sample dataset, available from -https://grass.osgeo.org/sampledata/north_carolina/ + ## Notes Since 2020: For a more advanced test suite, see - https://github.com/OSGeo/grass/actions + Until 2019: For a more advanced test suite, see - http://fatra.cnr.ncsu.edu/grassgistests/summary_report/ + From 7bae56180d787be682d5a50dd8734d76f1b3736e Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Sun, 9 Oct 2022 05:10:46 +0200 Subject: [PATCH 043/123] wxGUI: set window offset (OS panel) for single/multiple window mode (#2417) --- gui/wxpython/lmgr/frame.py | 7 +++++++ gui/wxpython/main_window/frame.py | 13 +++++++++++-- gui/wxpython/mapdisp/frame.py | 10 ++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 0f0b09a0e58..b26d7b476f2 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -255,6 +255,13 @@ def show_menu_errors(messages): try: x, y = map(int, dim.split(",")[0:2]) w, h = map(int, dim.split(",")[2:4]) + client_disp = wx.ClientDisplayRect() + if x == 1: + # Get client display x offset (OS panel) + x = client_disp[0] + if y == 1: + # Get client display y offset (OS panel) + y = client_disp[1] self.SetPosition((x, y)) self.SetSize((w, h)) except: diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index 19fa9802ce9..32abfc032c5 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -177,16 +177,25 @@ def show_menu_errors(messages): try: x, y = map(int, dim.split(",")[0:2]) w, h = map(int, dim.split(",")[2:4]) + client_disp = wx.ClientDisplayRect() + if x == 1: + # Get client display x offset (OS panel) + x = client_disp[0] + if y == 1: + # Get client display y offset (OS panel) + y = client_disp[1] self.SetPosition((x, y)) self.SetSize((w, h)) except Exception: pass + self.Layout() + self.Fit() else: + self.Layout() + self.Fit() # does center (of screen) make sense for lmgr? self.Centre() - self.Layout() - self.Fit() self.Show() # load workspace file if requested diff --git a/gui/wxpython/mapdisp/frame.py b/gui/wxpython/mapdisp/frame.py index 794ed1dd218..5d26c4b9fc1 100644 --- a/gui/wxpython/mapdisp/frame.py +++ b/gui/wxpython/mapdisp/frame.py @@ -1714,16 +1714,26 @@ def __init__(self, parent, giface, id, tree, lmgr, idx, Map, title, **kwargs): ) ) # use default frame window layout + client_disp = wx.ClientDisplayRect() if UserSettings.Get(group="general", key="defWindowPos", subkey="enabled"): dim = UserSettings.Get(group="general", key="defWindowPos", subkey="dim") idx = 4 + idx * 4 try: x, y = map(int, dim.split(",")[idx : idx + 2]) w, h = map(int, dim.split(",")[idx + 2 : idx + 4]) + if x == 1: + # Get client display x offset (OS panel) + x = client_disp[0] + if y == 1: + # Get client display y offset (OS panel) + y = client_disp[1] parent.SetPosition((x, y)) parent.SetSize((w, h)) except Exception: pass + else: + # Set client display x, y offset (OS panel) + parent.SetPosition((client_disp[0], client_disp[1])) # bindings parent.Bind(wx.EVT_CLOSE, self.OnCloseWindow) From bb29cefff29bb8bd18d678f949bf7656024877cf Mon Sep 17 00:00:00 2001 From: "Francisco J. Solis" Date: Sun, 9 Oct 2022 10:21:46 -0500 Subject: [PATCH 044/123] configure: remove unused wxwidgets compilation configuration option (#2593) The configuration option wxwidget has been removed Refs: #2578 --- .github/workflows/osgeo4w.yml | 2 +- .travis/linux.install.sh | 1 - .travis/linux.script.sh | 1 - Vagrantfile | 1 - configure | 14 -------------- configure.ac | 6 ------ mswindows/crosscompile.sh | 2 -- mswindows/osgeo4w/build_osgeo4w.sh | 1 - mswindows/osgeo4w/package.sh | 1 - rpm/grass.spec | 1 - utils/vagrant/compile.sh | 1 - 11 files changed, 1 insertion(+), 30 deletions(-) diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index e645585dcc1..4db5f0da9e7 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -39,7 +39,7 @@ jobs: $exe = 'osgeo4w-setup.exe' $url = 'http://download.osgeo.org/osgeo4w/v2/' + $exe (New-Object System.Net.WebClient).DownloadFile($url, $exe) - Start-Process ('.\'+$exe) -ArgumentList '-A -g -k -q -s http://download.osgeo.org/osgeo4w/v2/ -P proj-devel,gdal-devel,geos-devel,libtiff-devel,libpng-devel,pdal-devel,netcdf-devel,cairo-devel,fftw,freetype-devel,gdal-ecw,gdal-mrsid,liblas-devel,libxdr,libpq-devel,pdcurses,python3-matplotlib,python3-numpy,python3-ply,python3-pywin32,python3-six,python3-wxpython,regex-devel,wxwidgets-devel,zstd-devel' -Wait + Start-Process ('.\'+$exe) -ArgumentList '-A -g -k -q -s http://download.osgeo.org/osgeo4w/v2/ -P proj-devel,gdal-devel,geos-devel,libtiff-devel,libpng-devel,pdal-devel,netcdf-devel,cairo-devel,fftw,freetype-devel,gdal-ecw,gdal-mrsid,liblas-devel,libxdr,libpq-devel,pdcurses,python3-matplotlib,python3-numpy,python3-ply,python3-pywin32,python3-six,python3-wxpython,regex-devel,zstd-devel' -Wait - name: Compile GRASS GIS run: D:\msys64\usr\bin\bash.exe -l (''+(Get-Location)+'\.github\workflows\build_osgeo4w.sh') (Get-Location) diff --git a/.travis/linux.install.sh b/.travis/linux.install.sh index 640228043b9..ffdbebcb106 100755 --- a/.travis/linux.install.sh +++ b/.travis/linux.install.sh @@ -26,7 +26,6 @@ sudo apt-get install --no-install-recommends \ libreadline-dev \ libsqlite3-dev \ libtiff-dev \ - libwxgtk3.0-gtk3-dev \ libxmu-dev \ libzstd-dev \ python3 \ diff --git a/.travis/linux.script.sh b/.travis/linux.script.sh index 162b5470083..416a072d0f1 100755 --- a/.travis/linux.script.sh +++ b/.travis/linux.script.sh @@ -27,7 +27,6 @@ export CC="ccache $CC" --with-freetype-includes=/usr/include/freetype2/ \ --with-postgres-includes=/usr/include/postgresql/ \ --with-proj-share=/usr/share/proj \ - --with-wxwidgets=/usr/bin/wx-config \ --with-python \ --with-cairo diff --git a/Vagrantfile b/Vagrantfile index 0a47b641568..16499ba3f8b 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -63,7 +63,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| "proj-bin", "libreadline-dev", "libsqlite3-dev", - "libwxgtk3.0-gtk3-dev", "libxmu-dev", "python3", "python3-wxgtk4.0", diff --git a/configure b/configure index ed817c2de1b..5bb0520d99e 100755 --- a/configure +++ b/configure @@ -893,7 +893,6 @@ with_zstd with_gdal with_liblas with_pdal -with_wxwidgets with_netcdf with_geos with_includes @@ -1639,10 +1638,6 @@ Optional Packages: enable PDAL support (pdal-config with path, e.g. '--with-pdal=/usr/local/bin/pdal-config', default: no) - --with-wxwidgets=path/wx-config - enable wxWidgets support (wx-config with path, - e.g. '--with-wxwidgets=/usr/local/bin/wx-config', - default: no) --with-netcdf=path/nc-config enable NetCDF support (nc-config with path, e.g. '--with-nc=/usr/local/bin/nc-config', @@ -4490,15 +4485,6 @@ fi -# Check whether --with-wxwidgets was given. -if test "${with_wxwidgets+set}" = set; then : - withval=$with_wxwidgets; -else - with_wxwidgets="no" -fi - - - # Check whether --with-netcdf was given. if test "${with_netcdf+set}" = set; then : withval=$with_netcdf; diff --git a/configure.ac b/configure.ac index 15ce23e72b5..c23eeb138c1 100644 --- a/configure.ac +++ b/configure.ac @@ -310,12 +310,6 @@ AC_ARG_WITH(pdal, e.g. '--with-pdal=/usr/local/bin/pdal-config', default: no)],, with_pdal="no") -AC_ARG_WITH(wxwidgets, -[ --with-wxwidgets[=path/wx-config] - enable wxWidgets support (wx-config with path, - e.g. '--with-wxwidgets=/usr/local/bin/wx-config', - default: no)],, with_wxwidgets="no") - AC_ARG_WITH(netcdf, [ --with-netcdf[=path/nc-config] enable NetCDF support (nc-config with path, diff --git a/mswindows/crosscompile.sh b/mswindows/crosscompile.sh index b879c3f8695..2cc0da29711 100755 --- a/mswindows/crosscompile.sh +++ b/mswindows/crosscompile.sh @@ -131,7 +131,6 @@ LDFLAGS="-lcurses" \ ./configure \ --with-nls \ --with-readline \ ---with-wxwidgets \ --with-freetype-includes=$freetype_include \ --with-bzlib \ --with-postgres \ @@ -189,7 +188,6 @@ PKG_CONFIG=$mxe_bin-pkg-config \ --host=$arch \ --with-nls \ --with-readline \ ---with-wxwidgets \ --with-freetype-includes=$mxe_shared/include/freetype2 \ --with-bzlib \ --with-postgres \ diff --git a/mswindows/osgeo4w/build_osgeo4w.sh b/mswindows/osgeo4w/build_osgeo4w.sh index 0c1c10d0460..6da7e9eed5c 100644 --- a/mswindows/osgeo4w/build_osgeo4w.sh +++ b/mswindows/osgeo4w/build_osgeo4w.sh @@ -45,7 +45,6 @@ export ARCH=x86_64-w64-mingw32 --with-fftw \ --with-nls \ --with-readline \ - --with-wxwidgets \ --with-blas \ --with-lapack-includes=/mingw64/include/lapack \ --with-freetype \ diff --git a/mswindows/osgeo4w/package.sh b/mswindows/osgeo4w/package.sh index c0750583db7..2428924ef60 100755 --- a/mswindows/osgeo4w/package.sh +++ b/mswindows/osgeo4w/package.sh @@ -190,7 +190,6 @@ if ! [ -f mswindows/osgeo4w/configure-stamp ]; then --with-lapack \ --with-lapack-includes=/mingw64/include \ --with-openmp \ - --with-wxwidgets \ --with-cairo \ --with-cairo-includes=$OSGEO4W_ROOT_MSYS/include \ --with-cairo-ldflags="-L$PWD/mswindows/osgeo4w/lib -lcairo -lfontconfig" \ diff --git a/rpm/grass.spec b/rpm/grass.spec index 990f92e0c3a..d3e9adfea45 100644 --- a/rpm/grass.spec +++ b/rpm/grass.spec @@ -221,7 +221,6 @@ CXXFLAGS="-std=c++98 ${CFLAGS}" --with-regex \ --with-openmp \ --with-gdal=%{_bindir}/gdal-config \ - --with-wxwidgets=%{_bindir}/wx-config \ --with-geos=%{_bindir}/geos-config \ %if (0%{?rhel} > 6 || 0%{?fedora}) --with-netcdf=%{_bindir}/nc-config \ diff --git a/utils/vagrant/compile.sh b/utils/vagrant/compile.sh index e726ccb95c7..1f620fced5c 100755 --- a/utils/vagrant/compile.sh +++ b/utils/vagrant/compile.sh @@ -43,7 +43,6 @@ if [ ! -f "include/Make/Platform.make" ] ; then --with-postgres-includes=`pg_config --includedir` \ --with-mysql-includes=`mysql_config --include | sed -e 's/-I//'` \ --with-proj-share=/usr/share/proj \ - --with-wxwidgets=/usr/bin/wx-config \ --with-python \ --with-cairo \ --with-liblas From 9a5f274ca889aefa321a64100da9ebe7d650f45f Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Mon, 10 Oct 2022 04:32:39 +0200 Subject: [PATCH 045/123] utils: fix date and time format retrieved from the module source dir (#2595) Same date and time format `"%A %b %d %H:%M:%S %Y"` (example Wednesday Oct 05 06:42:36 2022) inside manual page for all use cases: 1. Core modules compiled from Git repository, with date and time retrievied from the last commit. 2. Core modules compiled from tarball without Git repository and without applied official patch core_modules_with_last_commit.patch, with date and time retrievied from the module source directory. 3. Core modules compiled from tarball without Git repository and with applied official patch core_modules_with_last_commit.patch, with date and time retrievied from the core_modules_with_last_commit.json file. 4. Official addons with date and time retrievied from the last commit via GitHub REST API. 5. Unofficial addons with date and time retrievied from the module source directory. --- utils/mkhtml.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/utils/mkhtml.py b/utils/mkhtml.py index f39abbf168b..f7d9054dc16 100644 --- a/utils/mkhtml.py +++ b/utils/mkhtml.py @@ -26,7 +26,6 @@ import json import pathlib import subprocess -import time from html.parser import HTMLParser @@ -152,18 +151,22 @@ def download_git_commit(url, response_format, *args, **kwargs): ) -def get_default_git_log(src_dir): +def get_default_git_log(src_dir, datetime_format="%A %b %d %H:%M:%S %Y"): """Get default Git commit and commit date, when getting commit from local Git, local JSON file and remote GitHub REST API server wasn't successfull. :param str src_dir: addon source dir + :param str datetime_format: output commit datetime format + e.g. Sunday Jan 16 23:09:35 2022 :return dict: dict which store last commit and commnit date """ return { "commit": "unknown", - "date": time.ctime(os.path.getmtime(src_dir)), + "date": datetime.fromtimestamp(os.path.getmtime(src_dir)).strftime( + datetime_format + ), } @@ -266,7 +269,7 @@ def format_git_commit_date_from_rest_api( :param str commit_datetime: commit datetime :param str datetime_format: output commit datetime format - e.g. Sun Jan 16 23:09:35 2022 + e.g. Sunday Jan 16 23:09:35 2022 :return str: output formatted commit datetime """ @@ -283,7 +286,7 @@ def format_git_commit_date_from_local_git( :param str commit_datetime: commit datetime :param str datetime_format: output commit datetime format - e.g. Sun Jan 16 23:09:35 2022 + e.g. Sunday Jan 16 23:09:35 2022 :return str: output formatted commit datetime """ From 2deeedd9ae6912fe7779793b4c65869d8fd80098 Mon Sep 17 00:00:00 2001 From: Ondrej Pesek Date: Tue, 11 Oct 2022 09:08:40 +0200 Subject: [PATCH 046/123] g.gui.gmodeler: add PyWPS export option --- gui/wxpython/gmodeler/frame.py | 232 ++++--- gui/wxpython/gmodeler/g.gui.gmodeler.html | 130 ++-- .../gmodeler/g_gui_gmodeler_python.png | Bin 16647 -> 120722 bytes .../gmodeler/g_gui_gmodeler_python_code.png | Bin 16854 -> 110861 bytes .../g_gui_gmodeler_python_code_result.png | Bin 13366 -> 134932 bytes .../gmodeler/g_gui_gmodeler_pywps_code.png | Bin 0 -> 123154 bytes gui/wxpython/gmodeler/model.py | 640 +++++++++++++++--- gui/wxpython/gui_core/pystc.py | 10 +- 8 files changed, 771 insertions(+), 241 deletions(-) create mode 100644 gui/wxpython/gmodeler/g_gui_gmodeler_pywps_code.png diff --git a/gui/wxpython/gmodeler/frame.py b/gui/wxpython/gmodeler/frame.py index e7ec49eba3d..f9b54926aa5 100644 --- a/gui/wxpython/gmodeler/frame.py +++ b/gui/wxpython/gmodeler/frame.py @@ -17,7 +17,7 @@ (>=v2). Read the file COPYING that comes with GRASS for details. @author Martin Landa -@author Python parameterization Ondrej Pesek +@author Python exports Ondrej Pesek """ import os @@ -246,9 +246,23 @@ def OnPageChanged(self, event): self.pythonPanel.RefreshScript() if self.pythonPanel.IsModified(): - self.SetStatusText(_("Python script contains local modifications"), 0) + self.SetStatusText( + _( + "{} script contains local modifications".format( + self.pythonPanel.body.script_type + ) + ), + 0, + ) else: - self.SetStatusText(_("Python script is up-to-date"), 0) + self.SetStatusText( + _( + "{} script is up-to-date".format( + self.pythonPanel.body.script_type + ) + ), + 0, + ) elif page == self.notebook.GetPageIndexByName("items"): self.itemPanel.Update() @@ -1981,13 +1995,19 @@ def OnMoveItemsDown(self, event): class PythonPanel(wx.Panel): + """Model as a Python script of choice.""" + def __init__(self, parent, id=wx.ID_ANY, **kwargs): - """Model as python script""" + """Initialize the panel.""" self.parent = parent wx.Panel.__init__(self, parent=parent, id=id, **kwargs) - self.filename = None # temp file to run + # variable for a temp file to run Python scripts + self.filename = None + # default values of variables that will be changed if the desired + # script type is changed + self.write_object = WritePythonFile self.bodyBox = StaticBox( parent=self, id=wx.ID_ANY, label=" %s " % _("Python script") @@ -1997,19 +2017,33 @@ def __init__(self, parent, id=wx.ID_ANY, **kwargs): SetDarkMode(self.body) self.btnRun = Button(parent=self, id=wx.ID_ANY, label=_("&Run")) - self.btnRun.SetToolTip(_("Run python script")) + self.btnRun.SetToolTip(_("Run script")) self.Bind(wx.EVT_BUTTON, self.OnRun, self.btnRun) self.btnSaveAs = Button(parent=self, id=wx.ID_SAVEAS) - self.btnSaveAs.SetToolTip(_("Save python script to file")) + self.btnSaveAs.SetToolTip(_("Save the script to a file")) self.Bind(wx.EVT_BUTTON, self.OnSaveAs, self.btnSaveAs) self.btnRefresh = Button(parent=self, id=wx.ID_REFRESH) self.btnRefresh.SetToolTip( _( - "Refresh python script based on the model.\n" - "It will discards all local changes." + "Refresh the script based on the model.\n" + "It will discard all local changes." ) ) + self.script_type_box = wx.Choice( + parent=self, + id=wx.ID_ANY, + choices=[ + _("Python"), + _("PyWPS"), + ], + ) + self.script_type_box.SetSelection(0) # Python self.Bind(wx.EVT_BUTTON, self.OnRefresh, self.btnRefresh) + self.Bind( + wx.EVT_CHOICE, + self.OnChangeScriptType, + self.script_type_box, + ) self._layout() @@ -2020,8 +2054,15 @@ def _layout(self): bodySizer.Add(self.body, proportion=1, flag=wx.EXPAND | wx.ALL, border=3) - btnSizer.Add(self.btnRefresh, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) + btnSizer.Add( + StaticText( + parent=self, id=wx.ID_ANY, label="%s:" % _("Python script type") + ), + flag=wx.ALIGN_CENTER_VERTICAL, + ) + btnSizer.Add(self.script_type_box, proportion=0, flag=wx.RIGHT, border=5) btnSizer.AddStretchSpacer() + btnSizer.Add(self.btnRefresh, proportion=0, flag=wx.LEFT | wx.RIGHT, border=5) btnSizer.Add(self.btnSaveAs, proportion=0, flag=wx.RIGHT, border=5) btnSizer.Add(self.btnRun, proportion=0, flag=wx.RIGHT, border=5) @@ -2032,44 +2073,45 @@ def _layout(self): sizer.SetSizeHints(self) self.SetSizer(sizer) - def OnRun(self, event): - """Run Python script""" - self.filename = grass.tempfile() - try: - fd = open(self.filename, "w") - fd.write(self.body.GetText()) - except IOError as e: - GError(_("Unable to launch Python script. %s") % e, parent=self) - return - finally: - fd.close() - mode = stat.S_IMODE(os.lstat(self.filename)[stat.ST_MODE]) - os.chmod(self.filename, mode | stat.S_IXUSR) + def RefreshScript(self): + """Refresh the script. - for item in self.parent.GetModel().GetItems(): - if ( - len(item.GetParameterizedParams()["params"]) - + len(item.GetParameterizedParams()["flags"]) - > 0 - ): - self.parent._gconsole.RunCmd( - [fd.name, "--ui"], skipInterface=False, onDone=self.OnDone - ) - break - else: - self.parent._gconsole.RunCmd( - [fd.name], skipInterface=True, onDone=self.OnDone + :return: True on refresh + :return: False script hasn't been updated + """ + if len(self.parent.GetModel().GetItems()) == 0: + # no need to fully parse an empty script + self.body.SetText("") + return True + + if self.body.modified: + dlg = wx.MessageDialog( + self, + message=_( + "{} script is locally modified. " + "Refresh will discard all changes. " + "Do you really want to continue?".format(self.body.script_type) + ), + caption=_("Update"), + style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE, ) + ret = dlg.ShowModal() + dlg.Destroy() + if ret == wx.ID_NO: + return False - event.Skip() + fd = tempfile.TemporaryFile(mode="r+") + self.write_object(fd, self.parent.GetModel()) + fd.seek(0) + self.body.SetText(fd.read()) + fd.close() - def OnDone(self, event): - """Python script finished""" - try_remove(self.filename) - self.filename = None + self.body.modified = False + + return True def SaveAs(self, force=False): - """Save python script to file + """Save the script to a file. :return: filename """ @@ -2112,7 +2154,7 @@ def SaveAs(self, force=False): fd = open(filename, "w") try: if force: - WritePythonFile(fd, self.parent.GetModel()) + self.write_object(fd, self.parent.GetModel()) else: fd.write(self.body.GetText()) finally: @@ -2123,53 +2165,87 @@ def SaveAs(self, force=False): return filename - def OnSaveAs(self, event): - """Save python script to file""" - self.SaveAs(force=False) - event.Skip() - - def RefreshScript(self): - """Refresh Python script + def OnRun(self, event): + """Run Python script""" + self.filename = grass.tempfile() + try: + fd = open(self.filename, "w") + fd.write(self.body.GetText()) + except IOError as e: + GError(_("Unable to launch Python script. %s") % e, parent=self) + return + finally: + fd.close() + mode = stat.S_IMODE(os.lstat(self.filename)[stat.ST_MODE]) + os.chmod(self.filename, mode | stat.S_IXUSR) - :return: True on refresh - :return: False script hasn't been updated - """ - if self.body.modified: - dlg = wx.MessageDialog( - self, - message=_( - "Python script is locally modificated. " - "Refresh will discard all changes. " - "Do you really want to continue?" - ), - caption=_("Update"), - style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE, + for item in self.parent.GetModel().GetItems(): + if ( + len(item.GetParameterizedParams()["params"]) + + len(item.GetParameterizedParams()["flags"]) + > 0 + ): + self.parent._gconsole.RunCmd( + [fd.name, "--ui"], skipInterface=False, onDone=self.OnDone + ) + break + else: + self.parent._gconsole.RunCmd( + [fd.name], skipInterface=True, onDone=self.OnDone ) - ret = dlg.ShowModal() - dlg.Destroy() - if ret == wx.ID_NO: - return False - fd = tempfile.TemporaryFile(mode="r+") - WritePythonFile(fd, self.parent.GetModel()) - fd.seek(0) - self.body.SetText(fd.read()) - fd.close() + event.Skip() - self.body.modified = False + def OnDone(self, event): + """Python script finished""" + try_remove(self.filename) + self.filename = None - return True + def OnChangeScriptType(self, event): + new_script_type = self.script_type_box.GetStringSelection() + if new_script_type == "Python": + self.write_object = WritePythonFile + elif new_script_type == "PyWPS": + self.write_object = WritePyWPSFile + + if self.RefreshScript(): + self.body.script_type = new_script_type + self.parent.SetStatusText( + _("{} script is up-to-date".format(self.body.script_type)), + 0, + ) + + self.script_type_box.SetStringSelection(self.body.script_type) + + if self.body.script_type == "Python": + self.write_object = WritePythonFile + self.btnRun.Enable() + self.btnRun.SetToolTip(_("Run script")) + elif self.body.script_type == "PyWPS": + self.write_object = WritePyWPSFile + self.btnRun.Disable() + self.btnRun.SetToolTip( + _("Run script - enabled only for basic Python scripts") + ) def OnRefresh(self, event): - """Refresh Python script""" + """Refresh the script.""" if self.RefreshScript(): - self.parent.SetStatusText(_("Python script is up-to-date"), 0) + self.parent.SetStatusText( + _("{} script is up-to-date".format(self.body.script_type)), + 0, + ) + event.Skip() + + def OnSaveAs(self, event): + """Save the script to a file.""" + self.SaveAs(force=False) event.Skip() def IsModified(self): - """Check if python script has been modified""" + """Check if the script has been modified.""" return self.body.modified def IsEmpty(self): - """Check if python script is empty""" + """Check if the script is empty.""" return len(self.body.GetText()) == 0 diff --git a/gui/wxpython/gmodeler/g.gui.gmodeler.html b/gui/wxpython/gmodeler/g.gui.gmodeler.html index 515970f1434..9d5a359b9e4 100644 --- a/gui/wxpython/gmodeler/g.gui.gmodeler.html +++ b/gui/wxpython/gmodeler/g.gui.gmodeler.html @@ -38,6 +38,7 @@

DESCRIPTION

  • validate and run model
  • save model properties to a file (GRASS Model File|*.gxm)
  • export model to Python script
  • +
  • export model to Python script in the form of a PyWPS process
  • export model to image file
  • @@ -82,10 +83,11 @@

    Main dialog

    There is also a lower menu bar in the Graphical modeler dialog where one can manage model items, visualize commands, add or manage model variables, define default values and descriptions. The Python editor dialog window -allows seeing workflows written in Python code. The rightmost tab of -the bottom menu is automatically triggered when the model is activated and -shows all the steps of running GRASS modeler modules. In case of errors -in the calculation process, it is written at that place. +allows seeing workflows written in Python code, either as a basic Python +script, or as a PyWPS script. The rightmost tab of the bottom menu is +automatically triggered when the model is activated and shows all the steps +of running GRASS modeler modules; in the case some errors occur in +the calculation process, they are are written at that place.
    @@ -109,11 +111,11 @@

    Components of models

  • (C) GRASS module: module
  • (D) loop: loop
  • (E) database table: db -
  • (F) 3D raster data: raster3D -
  • (G) vector data: vector -
  • (H) disabled GRASS module: module -
  • (I) comment: comment - +
  • (F) 3D raster data: raster3D +
  • (G) vector data: vector +
  • (H) disabled GRASS module: module +
  • (I) comment: comment +
    @@ -143,7 +145,7 @@

    Components of models


    -Figure: A model to perform creation of parametric maps used by geologists +Figure: A model to create parametric maps used by geologists to predict landslides in the area of interest.
    @@ -163,24 +165,24 @@

    The workflow shown as a series of commands

     # input data import
    -r.import input=elev_state_500m.tif output=elevation 
    -v.import input=zipcodes_wake.shp output=zipcodes_wake 
    +r.import input=elev_state_500m.tif output=elevation
    +v.import input=zipcodes_wake.shp output=zipcodes_wake
     # computation region settings
    -g.region vector=zipcodes_wake  
    +g.region vector=zipcodes_wake
     # raster statistics (average values), upload to vector map table calculation
    -v.rast.stats -c map=zipcodes_wake raster=elevation column_prefix=rst method=average 
    +v.rast.stats -c map=zipcodes_wake raster=elevation column_prefix=rst method=average
     # univariate statistics on selected table column for zipcode map calculation
    -v.db.univar map=zipcodes_wake column=rst_average 
    +v.db.univar map=zipcodes_wake column=rst_average
     # conversion from vector to raster layer (due to result presentation)
    -v.to.rast input=zipcodes_wake output=zipcodes_avg use=attr attribute_column=rst_average 
    +v.to.rast input=zipcodes_wake output=zipcodes_avg use=attr attribute_column=rst_average
     # display settings
    -r.colors -e map=zipcodes_avg color=bgyr                                         
    -d.mon start=wx0 bgcolor=white                                                   
    +r.colors -e map=zipcodes_avg color=bgyr
    +d.mon start=wx0 bgcolor=white
     d.barscale style=arrow_ends color=black bgcolor=white fontsize=10
    -d.rast map=zipcodes_avg bgcolor=white                                                                                                 
    -d.vect map=zipcodes_wake type=boundary color=black                                                     
    +d.rast map=zipcodes_avg bgcolor=white
    +d.vect map=zipcodes_wake type=boundary color=black
     d.northarrow style=1a at=85.0,15.0 color=black fill_color=black width=0 fontsize=10
    -d.legend raster=zipcodes_avg lines=50 thin=5 labelnum=5 color=black fontsize=10 
    +d.legend raster=zipcodes_avg lines=50 thin=5 labelnum=5 color=black fontsize=10
     

    Defining the workflow in the Graphical Modeler

    @@ -195,7 +197,7 @@

    Defining the workflow in the Graphical Modeler

    module dialog window is displayed and it is possible to set all of the usual module options (parameters and flags). -

    +

    @@ -203,10 +205,10 @@

    Defining the workflow in the Graphical Modeler

    Figure: Dialog for adding GRASS commands to model.
    -

    Managing model parameters

    +

    Managing model parameters

    All used modules can be parameterized in the model. That causes launching the dialog with input options for model after the model is run. In this example, -input layers (zipcodes_wake vector map and elev_state_500m +input layers (zipcodes_wake vector map and elev_state_500m raster map) are parameterized. Parameterized elements show their diagram border slightly thicker than those of unparameterized elements. @@ -251,16 +253,16 @@

    Managing model parameters


    -Figure: Average elevation for ZIP codes using North Carolina sample dataset as +Figure: Average elevation for ZIP codes using North Carolina sample dataset as an automatic calculation performed by Graphical Modeler.
  • -

    Managing model properties

    -When one wants to run model again with the same data or the same names, it is -necessary to use --overwrite option. It will cause maps with identical -names to be overwritten. Instead of setting it for every +

    Managing model properties

    +When the user wants to run the model again with the same data or the same names, it is +necessary to use --overwrite option. It will cause maps with identical +names to be overwritten. Instead of setting it for every module separately it is handy to change the Model Property settings globally. -This dialog includes also metadata settings, where model name, model description +This dialog includes also metadata settings, where model name, model description and author(s) of the model can be specified.
    @@ -272,16 +274,16 @@

    Managing model properties

    Defining variables

    -Another useful trick is the possibility to set variables. Their content can be used -as a substitute for other items. Value of variables can be values such as -raster or vector data, integer, float, string value or they may constitute some -region, mapset, file or direction data type. +Another useful trick is the possibility to set variables. Their content can be used +as a substitute for other items. Value of variables can be values such as +raster or vector data, integer, float, string value or they may constitute some +region, mapset, file or direction data type. Then it is not -necessary to set any parameters for input data. The dialog with variable settings -is automatically displayed after model is run. So, instead of model parameters +necessary to set any parameters for input data. The dialog with variable settings +is automatically displayed after the model is run. So, instead of model parameters (e.g. r.import a v.import, see the Figure -Run model dialog above) +Run model dialog above) there are Variables.
    @@ -292,9 +294,9 @@

    Defining variables

    -The key point is the usage of % before the substituting variable and -settings in Variables dialog. For example, in case of a model variable -raster that points to an input file path and which value is required to be +The key point is the usage of % before the substituting variable and +settings in the Variables dialog. For example, in the case of a model variable +raster that points to an input file path and which value is required to be used as one of inputs for a particular model, it should be specified in the Variables dialog with its respective name (raster), data type, default value and description. Then it should be set in the module dialog as @@ -325,15 +327,15 @@

    Saving the model file

    For example, this model can later be used to calculate the average precipitation for every administrative region in Slovakia using the precip raster data from -Slovakia precipitation dataset and administration boundaries of Slovakia from +Slovakia precipitation dataset and administration boundaries of Slovakia from Slovak Geoportal (only with a few clicks).

    Handling intermediate data

    -There can be some data in a model that did not exist before the process and -that it is not worth it to maintain after the process executes. They can -be described as being Intermediate by single clicking using the right -mouse button, see figure below. All such data should be deleted following +There can be some data in a model that did not exist before the process and +that it is not worth it to maintain after the process executes. They can +be described as being Intermediate by single clicking using the right +mouse button, see figure below. All such data should be deleted following model completion. The boundary of intermediate component is dotted line.
    @@ -342,32 +344,45 @@

    Handling intermediate data


    Figure: Usage and definition of intermediate data in model.
    - +

    Using the Python editor

    -By using the Python editor in the Graphical Modeler one can add Python code and then +By using the Python editor in the Graphical Modeler the user can add Python code and then run it with Run button or just save it as a Python script *.py. The result is shown in the Figure below:
    - + - +
    Figure: Python editor in the wxGUI Graphical Modeler.
    +In the Script type combobox, the user can also choose a PyWPS export +instead of a basic Python script. A PyWPS process based on the model will be +generated then; for the PyWPS script, the Run button is disabled as +users are expected to include this script in their web processing service and +not to run it on itself. + +
    + + +
    +Figure: Python editor in the wxGUI Graphical Modeler - set to PyWPS. +
    +

    Defining loops

    In the example below the MODIS MOD13Q1 -(NDVI) satellite data products are used in a loop. The original data are +(NDVI) satellite data products are used in a loop. The original data are stored as coded integer values that need to be multiplied by the value 0.0001 to represent real ndvi values. Moreover, GRASS GIS -provides a predefined color table called ndvi to represent ndvi data. -In this case it is not necessary to work with every image separately. +provides a predefined color table called ndvi to represent ndvi data. +In this case it is not necessary to work with every image separately.
    -The Graphical Modeler is an appropriate tool to -process data in an effective way using loop and variables (%map for a -particular MODIS image in mapset and %ndvi for original data name suffix). +The Graphical Modeler is an appropriate tool to +process data in an effective way using loop and variables (%map for a +particular MODIS image in mapset and %ndvi for original data name suffix). After the loop component is added to model, it is necessary to define series of maps with required settings of map type, mapset, etc. @@ -379,7 +394,7 @@

    Defining loops

    -When the model is supplemented by all of modules, these modules should be +When the model is supplemented by all of modules, these modules should be ticked in the boxes of loop dialog. The final model and its results are shown below.

    @@ -441,5 +456,6 @@

    SEE ALSO

    AUTHORS

    -Martin Landa, OSGeoREL, Czech Technical University in Prague, Czech Republic
    +Martin Landa, GeoForAll Lab, Czech Technical University in Prague, Czech Republic
    +PyWPS support by Ondrej Pesek, GeoForAll Lab, Czech Technical University in Prague, Czech Republic
    Various manual improvements by Ludmila Furkevicova, Slovak University of Technology in Bratislava, Slovak Republic diff --git a/gui/wxpython/gmodeler/g_gui_gmodeler_python.png b/gui/wxpython/gmodeler/g_gui_gmodeler_python.png index 8f9cc07260c310f1c7fddf9be0b5aa855ab2768f..6eb219bc4753a58204b794cbc7aeb39bdf09f6ad 100644 GIT binary patch literal 120722 zcmb5V1yoes`!}78GSSRc%27RUG6LNypHP6e2yeKP9&a&k)kNL0}TZ^mR zvgO@fmwqr&QasmsP}}bcKM|<+SqFIb5aLQc=f3x6Snsy8-Q|jAtd+z3#Te8NdTuv& zbhd_{sg83>;x|BXcpH^=>&pHj2v4ZQlS0bxAZ%w>i=FFv0C5PGQmSAibfJ;jWiX=& z;Rut8y2s_T_o1}aS3TmKr6~g=tkt{^f1s~l{Bu+kKGx70naj$fVeul>mh1F`%jT2$ zu~$)1BI_0ZEMuhBAvt`FGgF}#Z@(UOuJ;HF>)yBgoX?hqo+0cY2g`H0F$$hx-q36O z9-FAS%_vtfpxYnB02j_Ja%t+)|5Cx%mY;wym5_pJXk}hMkwdS;oFppGWJ;80=VD=K zYKkgu!n&ik*E_X>5>jl4Wm1Ca(zGqqr*F{l?5B7XkdPOq+T#No34U9u9RtrjcmRPp-G0B6a_?Wm1I9T0<0n#UoibRvFXDAUqk4LQ zjxgm(@%+#VMh9^`3p4X61K^j%;L=x}n)4H+?QHENAjp_+BsWEXf!_VmDt z^(7lU+pB7L%{VuLM(|fEocU~bY_7^~x0cFwsi8=1?Sn#|v(b&!&byyI z(qPhuu$yahtx}!d(04Z0^gFm+#@&TA)piS^zoVZ_=Gs2rZ61n5jXfc(-ji{BT31^9G1`cZtWM%+76~=uK2!hZ!B; zKAKZSg(w0B30Se6egmU#)90<48SMYDH1T1_V{w_>@2 zvdfI8p{>AkqDBcS2t6BA;=ir_QvUl1M+R4<#3poK$lptbfwT3T7*L|+-L-+~Fj=mH ztQa(X_XX6-;pRXS%I|4FVIhlnvQSvfuExukELm>OJX3~lLbM$ny%9fJ3CI0x`NcE% zg8f^f=yyOUXAWB0j%P$fQ^`0+R0FAQ%+H94MtBM^G|G~dn)plZy=39o7(y&sjwP17 zFCorK;}hX&U9pE8cBxKRdttjb1p+GLh>T~&!on)$TUsLjdoP?75)g8_&+Z$4o;DIuumyLlvGG5=Qp=YQkgf}#Jwdre%ynE+< zgPad>qA42UmG!&wT=(4}i@Jl8H-6(jslh}{oMH%0KsVwVQO^skFuz8GtaNW?cK4bJ zAK&xO67enA)(>>EWgOHU}Ml*4{LU?b+;6|kq{ zriJ?Z`Dp0qboXXLIzBlNPfZ`j=~T(Xe&y&TshC;NtbWlp1n<`FL(k`%MQab|Wz;3_ zdtF{OU*F2@O}FGtl0q+G1HP9N_kDf+wimKRye=_5Kfs(4NhB14{C<7Dr^sMFW`TD8 zW1k85l#QxiPHsirAQbOU-W9citXBoL9EFw+okv1x6Kp~fm@3br-?dLS!Q;e8w;X)1kb|kWC4HR-qvV= zR75RNkruk6RvGl{V1z0l!DiBHHjaSs5#D1uUXipk`?g?#yfzrruYfO74Nw5#%((w3 z0EbpKbWD^|1(Si{%f$ty&bI-JDm7iruYC0R-&aLmQ27n*H2T9^O79fkvM`X03{6^A z)^l-A33Wth0n=OF9?N~F2+cVEx>->cg%1;hlR9zB5hwd?wxN!1T5Vv42VPrFlMYuQ z*qo$0LiWD;Y%sA)QpUItnI-o1iMqu#V1Gux`{|*j%E+9o@}k;JD~`@l;%1ATGPX0d z5$<;L<{I;HHMs73vqO!zXQL@E*UG#?@7%C{A9W10OCsH@t7$ z>jj@<;o%j=Ty`;y_Xyu1tYyvy}faohf8?^Wvy^(vJ@StI}Htu zD)R8$PLJ1tHa;*pWpo$n| zv}Dx1dRuE=M!g_ffwKi6=50&v`gn#zfZs^?Q>@YLxH|X&rq4Mj8j9CGwZyTq>yR`q z=x(J$#;-S2cfzz|l#ySyFH~qj`jE!&TqeS<>tUvxYgPV>O~_*eM!OL5YIO|^-mav< z!o@P_H%}V(jPzfuh-<#NPuJOXv3YvHBiqezuxYVA>!w7>`#8YePWKenOKmm)o6~9Z z#bDJcF(10Z)tuQEbzU-nAGkDbYV4c!5ZvKLfntlzxT?_a^k-@}$TiEgyRX z6VxBNNn!Q0EJWMDXZ~F0ux;*0;>LLh0DZ#J`i=Vk*Z|#E9x&_0D$WF{VCS#)#N7e6 zNYdYJH117nZ|XO|dJ==u^cUdcvTB|5Qtt*(S3SurpwCoS_%&};p zLIcqlrK=#wRd4UJBMZvdSbP<_$qF1ODrG7=Ldz13M)v2~bl#t0zB8d4SBxTt@Rrd6gYw9#VX2j<3^!s-P; z-}orNg$pO}d*DNFVjD4C$x}fOw%th|Q~8+-LbN{l5a|1<;-zJk4RrJMbtp1UkN$qS z-6jV>J>S^JY+VWoU+Pgg_+8UP&Dd^);V%{)k2QdYgirE(jP&`PM9~1&^*yT-`8|AK z-E=**<^d)K_b$@ICVYvFC3e9F5pz1wSt8=TUwS+*Oo@lqDJdzs36Q5dv?cpXH#jD* zRFH)U>}I z$W$d&3}~YP#BID9-Ix22l`*_EKl0Q$%4;GgOsL31b+*Q8h z#J-fbEThE7kNN`ZC%S85hNwnpwuX~4LS|@pvQ(M1(PMuwcStXV7eX7y7mC#9#uD- zcO@>8@|USwgB#$9ZQ{C_k=-&F@rlo-lG#m3AO2wIenvt>X{mb1!oebVpt{zr<~dIT zphL_OIsl0P;(Z3}8&LugrC_p(ju!@dTwL-i6H09ZcdRxutxL1Xqz4Zlj=yY*eL^GW ze@D&jy?tCQnf8vO4?I!L`}{1){6pgDH`BC6d&dq6Y|99 z1(N|2`M4c`%sbl=xj#2jqR1qk$%|h!(O<9jf;(*p;Kgz2^P;2YG{(K9Vh=DeM`~Q; z8eMlh=ie(?@P52^@1_~d7DLF;Utb>~j+Gd%5ZlUz65<6`*L}ji$@Uo{&M-Rx!l%@ceP&r6u!EdD%Sui= z5JyrNNVz36J_0n7Z9}44r;uy3v?xf4r;ea`4wzU{(x1KEqa})Yz)nJr+J&#D;FNr4 zerkRTvJs>zZ=;(;Rc&2)i6L#_V%O?q{AN##{7%_{r{%F9|3c4Hlh2*lwX)nhVN+0C zZ1&4*)3j>lB^wLl3*NA-EK`ECUYG8i5Pd=4m&r<`LA#&*nw`W+47tL;eG7=A{tuPU zT>!k2)Zja-`3fs(pqoLXG|yZe8)}oo7j;M1rKN{o0d!yM?&#<4PE$b9-KAfD9li(f zKkV+%Gm{5?2TgQz8@YI|@2>mX{zMH{+guYX8~kH0?rg@>r&e@@YX8$C{;Zk(KRs%! z0@?rRKNG5F{a3~HMnv~g%z^YUHin>yY1P$U;!wsvpI zKrEsH21;8KB}nvt4n(j2RFlsQGRAEpTwp?Jlk9r@`esZ=WstUC0O`B9Uhs&G{+*tcMdv?T znNVK-+nZ*sfy9WheJN_r{&v@?jt_XQ;@DAjan!0}uAy5uw;iwLP;PT`Ggj7r?+csMfSUMSXfsK~fke~q+MP5b0I{G;EL|;_~000`u zIa!i{H+O4mD|DZTD8cu<+jezrHI+;Fzl$!Un-OwFcsErtM->R8k+W0DKCqss)??x& zb|kdFkY$+WRkYr%Ga+F7^C)fkk_Ot>onzgX1DMnxmE1R*3EC;w6TaxV=^z^SbOXuu=_)L`sTnB!hTJjH;S>gaD`l(|R zm)?Ah@fNuUvZAJe74q45B1=4Gk`finr0J!CaaK7Ytt-`KiZurdjjlM1kj~{O>mauv(xU*Jpb3;$P)-pUUuhP2X6Ox=% zP`B{bVdZ@@aML+Vz-i^{itp(H!TH{ToU=OiLF2vy5HV_vdGW6}$AChGN#fjuGvc*1 z$1j`&DdFNrRh&1$XW=-xZI|R@OTH1+NK8+7L|rpM^^nDS*3%cB8<&vNPQ|ivm#NaY z$Q1`jO9*#1hv^9eq0aGwfWCm6Ldo1trS-n1h6&Z-#*!DKZO9z>O@*G3-`sqdnfVFSm65+mW1QbQ;L zboC%_3@ZSDwk}oi^&M6YkzCZSL)#EyK0-JzhHSNSPrfI}3}&;wOxG$9=xfU%osgq#DAVG8n)gNb+Gn@;PkI2tI5} zijSaZxKc&+;zAly)3}1QM=AQo{6|ysAkt$=VvfHg zBrIb6TrYCG2^1d}*k!Vrev1Sgja;{ZL|h&{pXG+lC!|l>v$~h=9l`6u0O`*%n5*Tx zdZ(pzGLo0+gj(?U-Ds|u+S_}&g^tj8ulX}Hp(www&~&4?5thdd-JKnGhv1PpJ@q+1 z5Zj;TND+jV8VHZEv4plE;hexkj)zRy1zG=9dfe>cQ2{?6#Kw=!OtBw<2Ov+hq=989 zCiRJ}iy)<@re^x+u{D@KjZFN^Hwa%Wb4U-e5yrXcIEBP_Jj|%$HQ7s+4f(FCZ_5TK zQ+!fV95f~bprC$p?ojtJwXmaFB?Z6|LiNSrx)0M`_`z}p(o2gi&D3#yW~)0zrOPd3 zhrFiKZ!LT;xDks^bKFS0+&mywWj9xSY>WNq(KnY~yqtZ|>#(0c*PyCk!_DjoH;ADh zGP8v|ZN@fBFKL)k&~y3hKJmZmU(m%ol@GdOQ)r8RYwtQGr6^3lk~g{^NKXxCl)qv{SAI-D-Hh$U#f5R5HWk8`94Vanz@giM zKkXQ9cjbNk?_!@^Yg%rnjXk9y32w_Yico(QLCeTUZbXwA7uvDnIBBEj$MCZkoe>CR zUDhML;aeS2h@}CFvgV)o1KN&)Oq=n&#XxX(V~3SZ1$6k(GQ6l{-hvDPlyaMR%mEgp*f}*00=whuOW{EDN4=2~ZD;1ON$*x92POboO z$siNss+sze%D(24D~e)+%ufUBbU=^=81JnA{W=km=y_D$h5a@nXMagm>zo#FdbnvI zS7h0olvr=eNKLcSDl8U+olj3*qJB^+*v+ZPzJ86CEgQMKy=l0-X*bsg<6Pd~<`vyP zXxzpYN{^G0kzt_Vx9?nnMg5MB9&2W)Y5MT<5fpO8{1ED+QnKG6A))`u^a0BE0HgMB zTHerK9ERLv$jVL|sq-i!gsS?Lo{k`7!NL>Mi{1{x16nt4BqZ)Rv zlRP_t7b-hSC^_b1*9v`u3>{+8OQb6pdbsV8Maq%F1;wQhaOxw{AmumX!k_o?D4A24 z%z!i{K-z8|d(0y|iixpFa3~(v+cc3R#h3rNrtw^d3%q1!e^DSqrz&>*QoPNVuzk*! zpLO%>&|_ZQW9e4F(0||U;OZJ(Fhd34_XBO2mzE`);3{1*x0PQ;7PCzmTf(TT#Scn( z1amrmS4Sr{WpQz7ihxXe!MjPyXUKCD;{Ty1cYhuM3@5fHW8(%h9`IzgLXu99Ss1v9 z(IkiUfRW%fnJ4XuY|Jl^`tK@%zCJ8aTv-Y;%VSoXcUeV@HW zKiioJoSzrHz3xfVcf0(Pi}w$M{7Z(0Un`6Y1gypq+%Xb-5O>6u#Za=KJ>^<&xcyG~ ze+kncoE-B1n=$eIfAOhbsVNB)S|rOa8rnI@Y$&=~+BPeK7QcM4y*!g@g}aJHvGt}2})4oK|f<>jA0 zf9^jaB9iy?6eJG&5%PlY@2q+p)kCh9Bu}*G6%-XNPL&0y>R=RQt^Kw8bA1B?;EN-Z zh-WiT@l}obZ>7Fm%&?jLAx4i*(3aFP#M*T?KZ0M0`MRRIFQ(&j1Y<@=)qA374ky6F zP_en9-lCy&hN26z6$H-iR9pdJ5STwj)UH<~Z!BbgpR;vixaojVRJ7R;d3t*4wQ{)` zpO2tJ56r5hyYGu$u4AiA6?t=SU(b!<3mLYxEp|j(bRrV;VO($z50gT`o}QI8ta(rB z{mBWJrN#Z_(6BDDrxMaiuPQ1k&bCI-)8KV{ZKj7JhXE4`MMY)yJ8%CZg`P}sk|hV) zOFecGCYs%7V~VCK)PrTPefdcVt-A<(Io0=b)?IU8D3F!=GW`J~Ak5lzvFNCS zjP(iD=kd_~N0ZD>CD7AIQ}(6{>P z^t@YlTq<3@d74?c)8zt+zV2IoPwlVrC*t1ct&E{tU!$X+^e88{XMMrG+&k6LcU^gN zXJ+kg>WFiU`6pU5C9S@+jF<`$we+C2tD|CguGu-IS2r95lR*%1aBrkJ;$UGgU5F3} z4{$W?@tB&LirV=g4%Ww1LETeRNquolgj7`fRyIn=CJ*DWMWnu%`D0WXcOVHlvyPG7 zNSZ2j9r6>!?cz(Pn?>_KmM1*|4#u^q$5`h-{FHo(+XiuJ=l1{n**qGZD*IjGg?TG_ z_E0I}>}E<^UIvSX?K*n!hAma@rwjZW^Tn)hi*S!eT2lE|p2OC3^NXaj%s1bRzG+7- zML$-2Oe$>sA;OL$4?Ah#%h>kMZD((P53&OkImg;B{v_X|TW|o#!zBA6c^b8|;9%a0>^pRCr z_ro%m&=M)T+03EL3_mAL5T~;`HAB zM6W~A`12#yIf{x`3rLo1D?R;(EULJz2T8Tq^m^tSPDurg(faxpm6gUfR#-77Je${y z@iKke;My%XN(m{(=iTKpuRN97+*I=77!(t^-1pvF45#-^AFuTd4VfRzH|YE9*FbAk z#gXw9YdtY(X#?p(F4on2p9v?vpq9ePpk~OqO!hxPik!C5f;($l&Z2VHhrOroYpg_) z^tl2mq^<;hO%ut0s$BZGDBsC29q0p+F4!18yWX9zqWYyJc5}1kb)Eadhovm^v@u9l zzYYeAsiMRGsRgJ9y|0|Hm6nquBqHiwtoCcJ`eRTELNzi*UVUYeBP!$Yji|R65~}y1 z!gRr3-CTpkpO&8O2xi_~F#FA(o6ppm+s@a;^r173wAq2mB1hgA#vS$EkOJE+J9NGy z?e9k8P^dE6TSq0~dSYCAdqkSDF}rj{TK{YQgtR;5a16dTOsN91*c?5z61Wg4W89r8 zQT<+C9*r#<{`@8VpQH{0K|B81)(bi!e}BQELasU6&xrlq8BRvVpwnPHbL17gST9qu zt?Fu$Tau6)XB1dQ_9*e5d^^z8thouy(ADegX)L4iC*D1Dp})wUJ89gll16vg#LAwr zc`Fch{35sl<@i*B_Ivf=@0d1}r7)`AjU_`@z@TywW??>)%gf~T@Cha5VEFb})J&^y zcj!Z}(v6bEzT)+{>9iE1L%%@_On*J5d&`gaB;OS=aoMUFM(t~Qx$rj&yk{c@tjzlQ zx|z8-_lG0nlhf0b>-8kQIUZgcJDZpA0&F97_0FFmgekY@Y09bjphimA2>Z$7#V@G;?hh=gQiRiSVWfPfla2seZ6@~ZL*6WrC}H!G{N+1VdQ1EY5%vZ51cYR zO|DxL#6=U&OJyDydob+=v%wX}(g8FE^x3K7>(d9ppN-M*nlh@#HT`cdEkhleV}KO< z;A<1Lr$z1uIoaKkdz|a`#agT_fZNs79cDE`cO1?f2o|Kg5nQ((-5jKK-})_ljZtSe zu(MmbxxB|IWZ8q_LiSi6{H0~D=*v)F#;5z1tVPbLmM_VwQXIdF$QxE zvo@^Xh@m$-rdi`PIk%EgNmw%Tmd2s^s*r@vi8pNs@N;gE$dHJL_3IysfWH55+nwZ_ zTV1sVHlL{wd#Tb~u@uVlMW@Pw`(`iK;Oo`Yx@TnMA%xe0l6P#86^Gq(26Sxp`>nJW_sO0r9|ydmd3-s>MA4;idLyN64cHV z_%a-lQQ$l+FP7fVif#10y80PVRZttgpT1CQ(puxlUY(m}E@+OfTBnaW_-GBuoC{pwi2GL@qy4s?6ls^yiUHy6 zg(h%~ZiQ}%>)}Y?`hYf<|4lukk@2LXu#OuNZsrRo@-y;DNYuz3pFuPW8C5#;;7lUn z7Fq@nG31gL<`|i7r`$h$C#S*-S=Q8}bgMO2>j6UfLx#EKudHKYVqCYTQ!tI7!-N7x z%A5SSMw9DGM|C0xv;v%mIp-naU%$D`B^pMp&&9VeW#nLfm>a~=k)zfN)e0=SKUnCb zM*%GF7m`NHY*naegDlk*xm_IN#LVRH$Wm<7L9q-#gEr(p)rCbF?|fc~AdoY#PZtd( z$%UQ7uQ4+-TOD2S)QX393red8AEV`1CRCZY(8^=obG4`0+t$`Mwd~rEe0Uc2)6Chp zzQ6C+OViVH-z&tcwL@*gsVB;-#)}dJX$ttPjE21fc3eYind87Oz;fOHIdemCp_qC>)bIfDRUGJrQU7 zW1H1r5vl@S3&-Uu*!JlvBr+|hY|^>^S$HAKfe^M5KbTd&R5Gu`!G>R zgjnzZ2nS!TgSNvrfCNM7J;5CGdL&hSKle45ykp^nOe$uR#X7jeMzmuDEG(L*6ID0Oj;=6+w<7D&*=dq5M~+5Amd-{g0W;SYEK?kR?PaK%q!B zDPepI+a>Oc_kQFIL05&Pic7oc&|Ws`UFQaCHjeAvZg56v5Ni|B(u6^rKVSpK+HW3y(RYeM2$)6t{=&ACkby(cSCkhlC@3y`unr=>JAR@OQ?Vp z&;AP#sBMxSIRZ$5W#&SrkjrLFLc%(8U|f3opeo4jM8P(%|J}Q8m?}tWu-v4&@%GC5 zaBAmjSBT4!0|Y|i$ZP9=oY@>~%>0{lNbPiJ72J|LO>%z86g6ext6-&r(IN3M-EX*o z@2dF538S0g2eg-l^L>AHtp)|(FubkMV}W!q`ORaYhO&5)QLd2Iz~CqY$|}3lHxE5j zbKh0tV!OlK2+(YCvqxOsD-}Xxk(TN-n^ifW(2*bvGMaNOIWE}TYG!^ z!-yhb9S}0iAsHYDI6_4tQ${?M65`STeR|%PG2CtK0()6IGbjpwO%fVPdDC2#?3Q-Y z;P`Fusnu++NMf~Pl#VuK&5{=gDr4Btjn7a%FI+31z0xV|5AG1 zIEDJa>6#sk{D*&iGis~4!v>2Q-R-GEw#ibRu)~k&&q|C`{S_WxzK~mW6|Q)tc9|T0 ziT!e+Ewk03*?;ufy?Iw9F|s)t`0@=YsPtae-@w47-Q^I|PTqnp?}~p1E(DaT>LhO! z;Y@+M-$8=vO&yvOiwX>kRAzaIi81*VUR+9*?7ll;7|~_+Dd#PA?kM`jI_mYiH=OCT zy{db*_TR7?p3?f~Y*NbiF!g>u-huC9DWNboPFi{oqID1zIC@nNzaAmLfR}K#KNa=s z*BcA}b27w|2My@v2t5!JAMhlE&JO01fHUHke+UoSP`9!n%s@&>Dj3hCYQndVOe6=A zfn8>VCY_Hq=o52r((?Rs!i-qtXkv0fW!{iapk+ zU=M3<)#maHkU@-+YrI25tHej53*Dk}o#&vo5E9%wAlv3oi>R*`R8UZOImo#jIa22ndxp*LH*)6LTkgRx{aUTtnp8JhB(4f9O z|DlSj2PRcSCesT)>_=-+pCRLX^!WAY0ekzfDhML2`j8k;uzW_}b%#pDTt*x(7~Ll! zW6%#%RS0@><6A5v^M}n)X?V4pl%Jv-Urbub)wLxGNNy;rnb1-kG+@RpAP);*oME5j zWcY?Yb$!vRH9kJgo@v;G)}NNW5<%#*`TIY!pUL`9TJup`pfoaNs}dXY_;m4AY1@tI z{rfjI8OlatyKMmd$*i-rIQezjOdUM)U)i+{hW=9Xs1m#8|OwO@N-7-sX z;{z3Ji50w6DmIUo5BeThw5a>U-qsJ+-wY3u4_Sta`J5k3={W#Nm2?3^pNNwaXP9Y4 zP0i)?wScG6lqzY*naARvpfEZ9i}!hj)z$IGYrRuV5Q8eDs+MQxgMRGEDwl=(!f+Z` zY0Hm`>(pa7ca=y@e6oc&X&W2C_0LnEM_BhkpsmG<^wX=xi)F>YW?#%Q2<4z0jOIi^ zDKFbjpQ4oPRYDSRtF&a8^rugstgDma;~gDQ_w32Mu*jInwQ z0&gn)Z-X!daYkFR5Dw0bi5&ck2! z1>R%uVnDk&I<4eoQ9E=Mg5{IL?|tt}X0Ltm!@h8S-JWGYftj6+(W{**nf<^CEIi*a zDaNU;a}YL!2~@>!332IBCF6(?XO8LFiZC&e=-HQURMLSV=4WX47O=*1J;3@(q$kfB(J++HZ0C zPg?I1Y^QxW@7bZG-wsw_|4yNJskT&Oj#E@il@dWp`1Esw>nRq37pJ@_^1(Xbb|#G7 zS3%fHrcHzvgxI8JTItr=55*p~zTn}Bovs%IToADkfQ(jDM8xJ`lJe%zfP-EcFvsy4 z_-^*jw3wn>&1rMFOM@!$-n}&!@H`uyG&3U^6KxEoD8u=oq4&PEHoPvA--IXh;xxy( z)esMK$bWifaQz5-P-HPlja+%Io`0U_BoQ17XHpm?(XLlC1LCTDz-BHSz<z^k)93y3OQ5P%Aw~5xUz*rXP~8T^A{hFS3e%GzXw0OnJT5aPYQ~h2O+0*M z0q{@XP*2osiNFuG3e+6x!)I+qQR+>t+@!-&fMHmk4qFj@5JZ*lGenx#6*=H&S~piQ zS5!W??{-cE#0f~x8_O(D8gV zNx3AsPj?ml8_E1BYxsQQw`DqqU7Y8tg-2y8IByv68pc0xvay-%CJu>SYz}PAeE+yp zLh+DPrC;H(bMbrU@k3S5uwV z%(J)03ijoLdA6HX*cRgZOV3{LK3>3zYh<4z=?-JnjeX~9miwd6tdooSSTr&!a+xzJ zVx_orUsX7Fsi*?n>%H?^75WM*z@#f^Wp`Jv%I@UP!-(u!b)Fib#?MOf!wPuzjhU6r zZf@r&gVvzr!RkE(tw^g_+PB{y4jKy>{s|ZW#cp9MESt0Pj5yjteodMu+fY$;{O(n7 zL`S^YllTX$^2X~Djoa4H#^uba&U1k?UtB0MdkG zD{r>b0-jR@^+~+@AtGUd?`F+7aCXwX`x&XZ<|ZEKAOF*bR=46L;)?35ou)wr~ysqCr49R#oL799u zQ?bd>Zw3N>4!Oly)W-m?K|E=m;= zyx_p%bWy`=PihA-|7-bP(<)t0WbH`K-tZqs6S9R^urXvvy!2bCU>2uKuRUq=Ss(r~ z$?G!Wm}y&LHb&lLB_J$8sltR895>kI)y(a3>p-X0#_NYk!+{KF(ea72(!1Sp)|IU@ z8x=|#HCz-^gLmQVUvcTN@;z)-M>rEnv=Z?E-Y#kguUXVKC%(eJd;GFP8`Sq;~uihiv{ypTBOUX*#4AR_Nj<{VSe+b(eQON@kIY9)RR3m?Cij9dZ8HhezYlJHz=EuL+N z+mj0ZKuu#*1~#J+mVWc$r61@b;HJig`Hj3uS*B6O(yR^6N{jbLljx*a$-!?DOf?RM z3Xe&Hu1Ws_+vHz(OWkG=;#I>KL`wJBrZ;FuhUA$|5IqyC9(GR+?nxsf~@ z905a~*yz`gP=x_6pYyu+?8Kc?pI&mXGck(?xutoeJHN7s3lX=AQh0O2B4Eog6RsN4 zM5&T6CT+2ZHheG>3R0zv%q+uaFehpj*%Zlo(OIs;Znp6!?iq;zcx91yCRh>lt+_HB z4~wcow>W%HoFHk%bVN1GQIP6cBJt676tCCvYLCt`k+FTh{vO9Q8KH*GqOjyzkZJA1 z)!Y2Op;PitSViogI|sWX2vh-Tsp3zYvBl4^_8IB_-ieBMH)i&bR(#|vl&mkcm=hvD z*@SWN%1;?y>tt8&F)xPpD(VB?Yo+%%8o`vzA;$|F4Ds>to&<0VFAUeO2d|5gU(mGn zeC|$nXFFbT(ib{pN&L0=6+AiqHc^JbR5jvkBqY( zxH-i?KP{N_nz<)66%@Nd;yP^~8bKhPgdDV`1K>QWsBTkQ(MGb0x&_(y?@7_9*on2u z47;YevsDF)7FQh0z2W4-9tTQqZP_ID=Lki;UtNOiI!&z_9eh3`_C7jjKGVze{IvBE zeYf}>$|h)_dy)y-F2E9c1QjC}RQMZNUwT+Jl^>;$D*fi>tuw+;=}oxL$MFje4~=*v zdJH>f_DgWZ6al`m2-pJ5U)0>N9z~|(F-1>4r z1xHw&C`$lB4Ak8I7Uh8c{QO|gU4%-P(GdktIvJniy4|2vaJJb7T8TMF$F-r45KQ}pCITQRcW(`IrC z#v&1`6V@Ojo_8Y}+-Zr%HM&PYt~f!J#QE}(N5qG;iOy*Wzmzt*FX%c#ixCC)_J?Mr z>Jk^k7+%F@#iEt#*i9Gn``U`%R6A&7_f&&CP-G+;nxj7+^x`vkEHTL$N(pPX1u5kU zf}H~CcYq}IuKsg($V`eyMx+IIgHeA;F0V}@-)r{{+Km#_VgP&3MM#6yvd2$5aiN#2Ua|&@8ideLIn|(%@|0OlEsI_w;kWBr?~Z1 zR-2SX_TQU=!Sc$=KY+9ww0C=ZyI8*=vRuBg9TV`deFDNAxOp zkdwYSMBN0_lr_g@aJDI3>p7H6`HL9&r=%wo32p}Bmp^>S?->6du7+!2UlgJ}2D;7mSqiqFjb4r?k#d3k`+q79|uDe5bmh~6GG-s>XB;YcjA%f(7~IQ4Xz*TAF?J3pGGqY;}7Ym}YiGh>bg1905H z`f4Bs2rW7#4t7JttnX^ixl#7!*jkBcH$vM;tl+k{$Ynv3uN+pLd@{PZ<`_?~v~I6o z%JO)$jZttz|5Gabh0WZ+GjpFqzCRx(+)nOUaNfqi+6+2!u!q5e(f(`@w@WgQ47B@p zEAN%G?%N&UUwrbT<4PGM6?|D(d>HJCYXcef_aB~?HPfVb@JH~+!BV7)k`o_XJSew7 z=n^~JMt)m<4zu-cT2Rq37jk;)giAd34!w*XplD>5y{Mj%<>5ebc!NQOmk>q@V5&K? zbfrhK?eKGP8e{W~4=3#%9!-SxYQc)j4E4{qdL!6T?IeGGw8&3Y5me}AKxfW?#7$_Z z0+)~&c2A=|M>-xt>1qciHAwtbrTDqalFdahf>G3|)2e$cTMpj>b{o65XKQLYzw~5# zu|)(3keLq8d!6li5Oa@=KtH#1tvtW}O$)%26o6C&;#qoj~{#lXN+-JX+w7?X;GEZ*(nM5 z<}KukHRzallNaEt5A11E294jr!FYp4TmUC;zUh%;IyejK(7r9{St|esJ$Xu?37%u< z8s0dSS-cMDT0Ef*KNBc_b{o*=Z&usdr}p*7kvNX^-k)D*E?y$1`(IyZA?oH@>uWOa7RgZD(}gpn4K+vA9wVm2C+;q616yq*R3Q z+|di{QvdqPr_Kua{JKhR+ws4j0+Int`1ba8aOqWMXz1g9R#w1MWuoK%w46=+eNZsD z<98`gST#+~#z>QfFA!NDW0i?oOZJ9O6ce)s3TI3ibKj)4MS;9zye=>a#*bhj6p1ax$Cigj9o zR_~u_P9LR;)N4L0TOSk{52B~nDTW%?d_|C z3d4)|E&P+^CS9ILxWJn?Z=T;Kbx#96HZvzD@b2jOrjBjXv$H2mmgr5*`U3?-?FMC&y+B23u=n|QDdooJl8$@#3-C@&lda~#_ovc?G6ZxI1av|$ngR_uVkY{?6E6ep(%tkWkEXV^>;~_J&9rNh zCIRTZ6@v>Wn1uhl%kNkG^%7Kzo)wrHsH#eRaN!3soy}tx&Q?u{oy)8r0&H$;R!5c7 zSI3i&!?xYc>B~Cv7Q;xnSG5>EvnHtm9}iy0+U|?>!#&=}pPZBezOACW%E6)2f)s)o zsm`;V6f5L%EO`Eq$=X}|CvU{!pCTy@LAT?VGhRCB{f)>?`FJL6CT(F%P+#I__VH4^ z;8ZtjqPa4FJMiYgmdzaLMXPTHVi$^Yyx~(~>SYWE!w229?>=uz`aG?2po*}5l>^Ie zadNv_i$_nn=*&p^Qt$|mqvpf!6(0hAw+Cw&%`9`yXT}_cHMg=7{f|ra<$F5%&|XXU zuLOcyY|a_se<*!z)}4jM+PjrFsSoP0Fq2kM3yBFvHP#nXr9-M9q%>fPl=C)=-W3Ib zoq2rZB6F7Oa+hjvO|_WCu7mHwg;0` zI1lI1AES)6Ojo(N$eqrPzYleO5tjc8a_ZsEs^iyu-sqWEF_a6GA5|9~74mx~xG)jN z`I~a{rQLF#M~bJ5>x<{*r@pdRLir;vj=J!z#`B-j($WGYoh#eh^6u{Z+NJumoSabu zNt`Y#ofwf+B0V95OkekwGQTk@_cH{gx%u;i%g3QY${gOMKC6sj;VcgW zKgP#D<9ApbG&1!1A!*u3MbnBDSiITHyYTc%jy;o8(Ollv*Ry<_?jS0WX}M@?)Ai>& zC+`ii;Z?pyAT1JV-oMGp!k_z?%i&aXY`1_@1;h9vsjGwt&+)L^RR9tk-`(P#i58i; zg#G&7m%LALRgsQ+&29q{M0u9Ksz@Vb`6+Lx4;2Sr6*bR!Alwt)@F9Ku~}v=XBUGTViq;Qw8%!>d7-UYzOQ z8J!et=UiFfFsTY!StulW`~JWJ)#`UA0590};%$`He^|gQ3(n0*$$*#lDlG9g5yZFR zg{Xd`Bm0s2hZ{qhaerUh$$792%?G7%1&_&z-v{3#>od}5uzw&2@w^uh9`8_I!Mqeq z6%-Wot z?f>EIJ)ok@mM+jX!6*s}3QANIP)U+A7?C6>C{bu6BROXpN0B5TAW5Q66Vh0WS4KhjU~)}YPLQ@ z@f785|7kZ(koV zdD|(}fwJL1;Ta?nIn$ANuR8KGGE;l5_w|%3!8JNMzmFd!FxEzki2-X>85UM?5}2AV zZ5wO`Zhs@r6*t-V``8qJ^bu(*(<_PNC*PeoKRz`oJKbzhGFV$x<;qY|Zp+TpXvxgO zLl)EOUQ!~&&CT8OVM#s9^D)}lNk=NG8r;!6g+>(M&ZFbt2#^eBfeq%7mBqo*+zczU zE#n@(a<1Wvoz=~iHilxuxU0F;yYG?G3ClZgK1VHji`%2nH*F}x=;r35t^A<(_X#$I#DhmsE_sP)ng1b<*X+ba$1_Z)bH(|A)1n^6Kou(*)iSG(C~BK z^p`LW{DGOYGjMxR{cZ4-U&-KPQUo$FX2IDS5$@f*Pme9I}W&-J@ zu-q`6O}x9c`)p+KoXo1&@I4#4_z1IyAz7AZ>U7%~uf@0PHurZ1cs!J0$Xu(@);T#u zfxA(wMmtOIk!8my+6T6%R@UFnH)7FN<7zkduY8WT3Xibe?q#scZI9XPciJ&ucgLH zx-5UK9&?i$-SkD2S+?CUIYXFRjfWha{Fie|fTNkBR=?_I8f(U*_ma z&wusPWzY)!-AnklW4F@N^7j_M|N7y7b=xJ^val|G&C&dACXb!^^zS`(?iaw}{r9KD zeb;#KujV~PzkgZ0<^R>5_g}xN#FWxRg46FKd$dk^uKdh)iDe4RuX) zJe!`qIfPUK%T;?PCdigm*R-ZsiUpkitipO>(7$evn7(KD7n9u{&1(n#_eWc!wx`C$ znUER&cU}*r>t*_x_-gg%+tdq*8BF)Z5iqOdrsp4Eb5Va$5r2J4w0%IlZoOd*f$njE zxi-IzvwtW}lX{hBU~GK6(pBLka_%|iLZS5!ITgQdjNfh#vq49mb2b+Oy|+Su!eWy4 zu#3l<`b0kRc}?w#F8QMNh>(rQvYLY(vOp)t?J1FjkR8L`Ojibe*AayhdfyzU@cE34 z_}oALJQ^?U6h+FcGJ-5(ak{E@nUAlxWAKwEgYedH1#!*LkD^8H@9@{J+nv!$t3mgN zObZ9}I9FO5m9kHrj597lWLfcB&Q*?9N&Z+iWPRDOraM;s2qB2cBBME&Me1bi%_1#+ z^v5xBz1&&7pKxnqu9x8P%>Lif(_f23Lc=DBFj2SV=;JgsRr~dsy68J5@1vr8Aw41t zx|8EjS|VzWBPUqYirtfvC>Bd})w+dl-0;{;kp868^ie8g3#JIPNAcNSCd9|bAEXj_ z&-;95_`YpZqloUm|Pn8gDuDR9eGuy$C#bTsO=2oqfxA4 z`jX^e6u+zTeohD*_G;vOuh(n*4UQM(Tg02cEmK*4VwnyKZ&B%R-fv+hXJUrDSY;Ds z>B{-7XaUE72y?`Af6oqX%)L$H0SVP>Acsvhg~`Q9To|;sxUSn0Z$7tWW^Qf~D&)Y; z5swm6j}h%iQ3;k2-X@!BiP9a&8~Rwi>HR|z%tv1D(5-0+G8XGEsZ|Rts~Z};%0#_^ zy5d79q^V6*=(mRo&ma5q^=r5R{7yS-)xEvFoclB}4_g*s%-?+IGJT}QCw=8?xK%Fkdcx|45nBYb>(EN3^)vl(dG zW?LC_Iqfq0=AkHMWMsU^);2e5AS*QlvsmnHnY|PJUDLJK>q z@vV!9e18X5(9WR^Q!369K}khvW@%nLv4zXgD?@1qz9}ksnWiJOJL@Qq8cfbu11s74 z(9o0T_XBU+W#!~l^;S&;VN-`pf9+>K3L+b_8%~?T(3#E}I)k?@m?K94d9DHSTC~!YK0+yA{mzSwHB)C^*-N9i7eJg+mNhew zYEmCLL%o7oT4QQB@^XIvT!; zEWPi;SNLu0JgXo58Ok-Q*&HQ;oV4P%o-2cAt>0BlCtx$L(KKUXYHErwHaYl}I#$#< zwA6T!ljZZk#tOFG{GjP^QrrIh9F3|QSZpT(gY9l)qH}&VQNi@LbXaMRTDVJ6NY;mv zl^+#Z8_|5Z_Im^PgZz~HSkDWLc9YWy4FbQq7SH+NONWxI*Z9)t!ZWsPG%PhAJ2Au(w2UGbs3 zj;Nmj|G#skb>4#c;vav6e9O?BDzG)Z!R?pgl(^PdyP+#eXw&h(^=@R z8|E^QS`?Y-^1gHBiVbH1Sg^mp0;a%vuIGg{7F=UfeK`huTVuZRo>G4&diXxRZ#@+C zg@@ex^rg(8EM3;+JamqF?fWiX-k!nb;-;_9G{t7S1eKHI`R?nhB2iebFdh?~t)-C% zeQ(cDRBy~f`fr|l68n`3_Lt}mDUUl3~vdkWQ}Jd1cL8bTT_4g z_H27=ETO?@Fn51Hdwo-Pk4Pk4h_9f3GUx3j4xQnVkvqQBLY~=RWv#- z|H3~GslVO;Jz)LWxj)~mvZf|WtBx44u{hMyktm0&73ceMG`~mRsq$%n{)f4qjJRfp z0V0v`@iY{cH9-ccwf4jM!A_(|R0V}evUca!;{Y498~($`^Ch-g}M?S^D%;(JWB1O!LPScr(kTg^*|d6T;?%Y;?e5s-!SB$5Q=8dr692D*-n z#9QZikQ~Y9wC6;;{h{}@u)s`b%hWtgwZd-C_N9Z}^4$RX#{L2l8Zxr|ff)RVnNE(X zkf5My@U~9(W-&nMez2i#V$u>IBV3oM-N5U#!|CkotTPW0hWEsfCOTDOcKj*kT5nNeSm0{4GDsXD9FXyP5quGgvzL7D;swTo) z>H>9jp*l`Go5;FySF<;7I->8n@h7WA+@5M)g@!f!VHwoR`UX}W{IZ%F*KQ=y$a?oZ zCKjix-EO3vaUJn!b7b7J^_izOHd9{MUFN}i2Z4-A7s(#NO|kqU=hk`hq$NC(;=S@M zd4_B12DiSmUUzr?_H9nk%Coc~=mjTv)1;Eq+I1mn=a9uIcJzF7&X` ze&oC|U4CLG?YX`(jXEaR2gPnd{{`|zI_{?m}t$=e3)y55lxa$F&0QqQ9+G#Br-uJ zs$LjKBPO#6B4wTo=_8_&(4Oy$v79F_>&w9&v0ZJt2q|5Apiol~Yk92Nd$u-|BY0~r ztEA)0$hXGOf%@|m<0&d^XIjmh*J$6(PbC9>Cp%Fq# z(NL&aV_SIVn2z=A+q5Lc>E2!~wSv3l1r~;UcK!jOp&i@v9YSTgEy9vQCMH2uH5Qk- za-gI*RCE>RsH+dfm z%;t1^g0E8O2aBoZCxB^zORP~qI#pS;2-SRhjV~E7RZYy(J)lTDWncG^A@Yk?O3In0 zu-zwdo{akXt_ittAC6t7r*D1QHdz?+uqDt+1vcR8@82J18Mw8b>i$7SX;|3xy{6{# zcB-$pxK!m?CppKdQ)4P;$!gv(tJK!ku^F_$H_49f<(2ZTYCIl%d=}M`m%VSD~5=woQ(W$&Irj4rAN>N^@Y9B{M({rw!i3df zax*s9^jAzI9EWDqj?&RLtQuc`^1()~fEHn5VuE1j;PA>;wHdiP5=^I4%b<*(Ex z%MBluhS$^uo)Q$*1=jQAkeW|Z^1cVUJ#1~w^7-@Ured$9vAVjr$R;5#pW(!AZr)=xbDlX#K^L2$iP$=@E~mbH>(*J9%AwI4(l8=W zX^27v7!9I$ccI8WB>8ajiCqf3@q~t&S{mA85e(Admv7$m?9I~E_7P+56xrO#j}9d)3TwJ|*W753e2DJfcSik8p%?Jr|v zwKAL>*mpOHqGjX!B?}a1=4+@mCq^oYbBw7NiD>B2Fl8q+G`4s>C{d_UJYSe zR+d?2mZsG1#&LxdiEbB!1~G}gpaJQlq-R&@7`^7}>gH%}xeR}O#&+>^WqfQp|CLup zb#>Rm8CB{c=}Suud7Z;WQ0o^GSk#zueP5?A%P>C|J7Z&mi+f+gDCP~ixpUm!z8#&J zsR!Ou;yD91Hz}k=YNxeUS|gAKrJ{tXT)up{{(D(n|D};@#!K_o#jT+OEHYj?Lc-XX zWge5qx_l>7T3WiQD*>HBRo2}6_5?xX7%saJkXA0wBr%K2v`qG7tj3oTkiF$_+{#N< z4lJt=bW2q340Oi+xx8ut!s0pE7`%p^wJY}R^cr%q@SsPkqAzC&8)32ALmTsA_*z#7Ou|dyHo=g^W4EdUxx<)`)-O}V;&%)9;*X1p)lD9JIc|lMK zjeCLKod#CY8Xi8TcVzO(!(nfZ4?54Wag(j4D~Q8eu6@(_3RTzPjULt1TLR+4`p`xZin@H6yv4AfuTokkB+=P&iV4_?bd{>`eO-CVnlIEmQuvISWHDjgSNG`_4hXXr|->g zI9)|KK6&z_N)4I_CRKe7U+@0-x6k*nPW5%ogqoJw|Kb2t((R|A5=wHr{A=@TaLKp$ zlbt`WC~*8RDxW)-lwton4Kscx{{NL#$&2_x!(&VdwECV=@1KqV7M~yv z=bD&Qt5A1`m8AcUe4T1xfh1AIhMa<%l4pH;Z`CPVj}4#5chl6GS|*I!qPJl6Ln0P( zo&CD9RGdVBnMIgbmd*h!ME6naU!M@5p8RKFZtmRLd+I7VFRL0uIiTXb8CA?hbkwd~8KG3k4Idw`lbY#RriH(4Y~-G% z8GK9s$ni*RT^&c0Q_{b#E^zy2S|kFbH9_LyeI|hZ5%(?tSk#5-Jm{O2ol5+&ar4>p zFV7lCTu7Ps5L*+$S8J`rah%B#1l;0z2Qf~+fKxk==BfiJfRKR^8InNn3JnU;X z715+)G4xgS*Q!}SY4bmcdjI~mgv6=WcxOhTd2@oe3}fP({spP0_vKmN>dGlkrxM*3 z{kKF15JLp$rGDJU?hHyr7JHXC$OJ?o6?b$X`e*Bn)MRSADWdmzHEWEo!Ict_3hF*7 zIt;z;{Rj1ypZCjN9Rt$(+@(u(KU!nNWn^@R%U)f$fDyWK^{Sg{k@SRQ+x2am^4>^4^w}C5BGS=S9}ufT-{Y zDQo9?v+7z}82I@=TF>__SCYs)eOmnc#|dPoo2h^+B_hHfhTRB0Up9vg!*`-rArOpy za-;riGE{nj_{;C_^+n2K$DdNj{sRz2V`F0#P;?*p0e%9wGZSpTF%Pv)v$-VeQ0Hpb z`O_gd^}f423gZq`koxWIiQcjQiv)RZSEyrQAFm7^yWvyXnH+JwLq~bqI zPOj|pM9H`vMM#+2MVKU2y1!$9 zQ+?awBpaNdJ=doF>odl8qM9B~(C(3*gVh|!qIeX}>jyjptlQTyF)`CSagxEcO-)r$ z8@$Xo1F1ez$RSgs>J+Ti6w<$@DgO1K6kAkfIv~$Q^!N7@W57&tk>66RAjM|kIbmeC=?LWq3G_uwfve3ArE-{h5w1OXa^J7agA0O@Ps zCVM~6cwlK|MWg!NrQbH2V6<`3T2sE+7=%sMzX;t$)PVp5s(4sBj(f{Bbdlei|7I)b z_WMIB4@TSqIQ5p!L58+lEMa~y$&V6t+s7)5PH>&1i9)qyO=(C+7OTHZlhY-C_H~cM zB|ksw;^|h>;L^}+E5<+unaOSKh9!^=LUSw_a)h^BNG&E!g&FW&S~llns>1nfi#Ms8 z$7-m@DXvb~y_VrPTq5hZH^z>VUwqs`^ZAVYSYw2~TQYFYlapxdQ z>;t>i9B?8lJR&%M-~~+W$=fqzxZn_Q0i}vpHD^6wq5D znr3L9EU;Z3HR?Zc7{Lm<|Asd>rlj3LKtKRkmztG{hESN9VrFKBW72HS_v9FyDBc=9 zaG-F|ap{}2e*j0*&e|f{-<4qOkCTaa+z71{OZZC%*S&T# z=beI?Ih@2>n}?#h@7?_}JFhy!pX5s&S5rY0V7o7PwL6W+0B#V4XpA2`i}ROwjQe@H z!Bzc{%RmwBEQHB3(S^cX$BC5XdF`Jk2*e~ME1H_T^9Jn+TwGib5Za2Y=Z~I}JbuYr z6z0H4X~J6fZq*wv*&Jl#HkRx{7TdDXIIW%2*VpIe<-KJ#dS4F15an17+fXsjn97Zi zN~0(J#rV`zuzgznXwhP6g&rq(!e8#JTo)1=7+uCywN(5c0EC0f2@m2*C2Xum^A&H; zi~)YEtgdE%*>QccF;tU#unjA;QhOC)*eko%@CBaJAnL#g_m#zZ=MXcE??0Jr#bMYFs@D|qYuQrT^L7PUqXS?X)My;&`?EtoLv8R@JdOO*K{UTcxn4MiNSLH@{A;{FjL%dSm zojYvmN2`T)A4wThz@Sqxn-6^J>YBs9yxGTvAg!!od(lA3?#$?Fp(-j(XjNRyq*mk; zOqR>dozKT>I{np7DH0yP3oVggiS05itf1p3PK2g%>9@VX`AYo!UTvBrY|VD3nY>I> zNTas1vx|+5J$v@7x|w5Dh9wsKD4~4=0|RyWBLrThPP;492~lmI9}s}xAO>8s@%Cc; zH999}8(J0?pL175(?P|O>+jygb%TRo_y~Cy0rQYQ(#*(kx;q*Q2 zFzxRx1C{Y_;QpX*swwQDjt;$M^}7*>E}Z&pv6ThJEPk@Y|BGk(!X!R;G{#RTL55=w zV}he3?j}fgY;NeRspWXr6}j%N{3{%l8+%F7eR!o1QW8TmX=m%H`C%Zq1$lLKfoKiI@MAG!=0+U$bczW zBHkTxM8Ya?C2&PbJp1}Iv48Vdg}PY^IOu-?s7FqMLP96coY96o97jK6QZ+P0;)306 zL72kcX%64UR+?43btO8Hlfib&OoPGD@KgXm$El@dvx0dm=Ji#RoaQ3D6YAjF(e`X5CL|<;LLk7R z9r*xeBE1b@kYTr9({prkdR4w_69GNO@B@^*re#kHC*k4c<)GgTMcSESvr1cmLf)#LiCyBXyt=LJ;y_Pfri1NQ+C*r4zQUl=Jd}7b){+@c{b0 zmV-T_7LkKurAt&O6l!j6PBBB{M2q0+X~>;$*Hq4j(ai?q`onD<9B`v;G!i1gp5de>GZr(2eq~G+BOLMT;?j1STDP3LN;*t_5Ilf^qVL$@ct_7K7wG!-{g}_6e{--D z5Cuwht&UcCNrl{c)z~Nn5EOvtC*79Fstqe(ByxqZ-t!2!^-PLOlql>hN-6!aj{?$2 z+}@tM#wUVjT{Zt!_(%mBCke@?3QBc;OgKx+Ni`5dj* zM$g9=3aec?+gTsz;E-D{jzVKZ73>mlMzCpA{*fiDgciyN7OmTI2VD$z-YZzm-UB88 z;VPRY7#Z?HSGVT#1FwthT7SfddViKrQ9gZ%{SEv;X!WB|c30Ri5G)@&etZ_S-GJ;V zu+Ru|Q3^YT3=gZrc*2%izXyxY#QSoM zBmu}hiqqV82WVkClb8^~Yeoy7B-5HV&ePL#6!KkTl*rI18|a6c03)D0a|8KVUfuHW zoy}Qm>l+c5mzVAwCBG2l%R0nQD|>~U>t!Wu#|CIKPob(;&C_lm1w46?*EBlk-VIt1 zyWYJ!4Seep9~zNn$dsWRy3(PO;6%8_&#x?gsN(wJhY+u$&H|y=MfmL|y;Mlqo0BBT zRH7Ly$kIm8x%nXbK}OI8`BM&Flj~1VG?+rGq?~*CX;w2Gb;)mk znH*~8(=+T5-10=f(98YGm&uWItk!f5dt>su*|I&`aR$Up^}%1e7;pB3L6_YucFHH0+18mlN4BWS|Yt6 zRYTQ*!=ezR0wN=uYyGamCt`xQ0|q3nWR<+s4r>Po2dEytjn@TuKrR6b25uuc?N~z9 z!PJMex94XqStA}o9SA-8$TVH)qdj54tbwKLPg zMFNDWgn94K3nW&d%imASp=T3jjujsNE)tIlT?{x}9Q{ScNo$V`4GlAhUNKMa&<2W_w$kEsT?a1Bf(WHl*Wvr-Ba3 z`__Mz5}|3fQXE@a6973mQk)=M5lPK>V+VDjXieFck=n;6Yr^)$Z(e(l*GBCV~BTD#n0-7PCU1NJSUL=4tN>swoGqL5BE55DqH;Z>- z6t7-~9h)6g)_sZLG$s)b^Z$_-PvbXxRlGN{JU%0g$rCMmo9?rBYjNT1GX(s3pCZQV z+B9>)Ux&N=wJ*(07*~H+iW~jQ=~U4)P-g_5B%w#(Jb*J@DF(|uOG~EYJjSPQL!5&; zv9wAPlF*|Feyb2Zi}-0}F){b)^2@3+R91G|KOkUvY3X_n)o@O?8i$we((t$VUDG7&#N=cqcpq?39*kiyt$cDe4L!NF zJf?$Fun{mON;G40*!7@P-Ch-Kv1~Q2npD`Pf0qIA{ASUxYIjkOv-X5)OW4;t&l1lm zzm`m3eNu2o8ajujLor##kDZQAl~vq~&R9ZnY4LA0I4L_1a8RXLo@|ml zbGw0!jSYC0n5Z3oe7_<`ystyXs&);sWpwoA_8j_0A5EcIpq(5PF9a`ebS2Gob>Au~ zVmhpW_23nKckx@QYLS%1V188FMsRqzl$u)P4G)x1X&A}+Kk~4OBhpwt=Gn6NzJT`B z)2%4Ch?t1p+2U|PIhw^CG(%^}tX)7h_ zt~29J=fgm^t$AJUv+$KGxRwOGGvt7>8I0{pIJJeWkjnlgpD{v$f}SPdP-`3{Q`o4f zt}ZTo->S#N<+EaH@tmjV+39YK1GHqrj>3@$aAX1#Y`u{Rx3Kk+&i%PL=K}^E6BDEs zv&mxleH$GeokX_4>eiUKocYDtGb&8^@{h;YQx+DRqFPjak%zZ@;fD6tCnx~P{{H^% z@7{sQr8PDofx~pTj5uv*5wLlI<+T4acHN(CBF=2AI-Y!i$HK-Y0T3w;;9AZPe|v3f zXE!o2VO3)QI@T{NOd#V5PC^yIQosoS`@)>eELQdHamx|`jN9U^QGeCFby_l1iQ*ND z1Zpv^5@|1)it1)O-;dP1g#x3py;aFV>*_b9)uegt_>=_EDX*E;_g!x*oq_rvZ0zRX z*1<&HJG_pY(xJrbP|)J;$@c0L2T%)8XN3qkSbKCY+Au3;s{@P&_Q_(h@lxs5sF!&J zs?6m`xS$=lcJa=^6ak1cw!8CrkLFp?d+a#XZ+BxJ=RvR;v~vqaIu|_e+Bn3XM_rLe zar3fBeQnImaV#z{H~2VWxU%wo5R0mEEC?>wfu)Auk9j`I(p+v#5IWSmqI>MagYvJ( z37PoIdXMRD@1sf+mRG$qY*_XhUg@y%jJYj~ye}3C{XliY&{>zG32Cerzb%9n%E-vN z;`~6+uGemSY9g4g8k`m!kY;{Ud>5W*r#?X?golTFrpTZ)cWJ6XoY@|6qxqtgMGx5e z7T|F~=<{LB+jeqtQUW3eM+ay(1i_;N0Z0F(@BaZar3;dc{ukm?60E_eaV(Q$Ex8Y~ z!oDEU!m!BqpixN22|fhmkKxr85eA6Tmi7n6A-$&b(;^9BgAXY_AF*ZJX7-xW+kPpT zi$+IuyiV*eMuw%*SaaoAL1VhLJvTuiQ<)xTTe|K&{?hggDK>sPzE-=Jx?Lp&J`?8} zPW~XieGsxw>f2I(({U*UT4bTr(pFYETn7t;|A{SsmwLBq#CsYdaK;Vr=)9v5iS)bb zwXc$|&}1OsTQ>MAo4T*B@6(6tFvB$=(%uvHCyq}ta63F%Vx_F%5I=GqsaM<)jiu#$ z+2L+8y_I@H?i`3u;dH;fjBc+_crT{!tpTBkZp<~ZW zbg0xpspwTg4f9;#wps?q_+ggoyA+bCe);nI@slIJ--lmG&fEY#9n1{!N|?6w6gyNZ=K4B=pIb$BbC{19p4#9Y)tTUjArlMT188C+ca~gcI&N3isD1ysKzb4* zcX~#;+1#%5$$d!-&4>MMeqP>m!(MhFi=TVD5{_Vd!fMX=4|U!}I2LKe+8+gcYI~8* z;;GQ0JDYf%KL(@kPNs?}WTrk&QR14hOs>eQK$pzh?SI+L%gFd-vp5J^rINt;e;$gT z!=MqvOpQ0iLq|tJ$snd9(NGHkBN@^MSGZFqd|kdCN7lklBSJv_#W9f_21Ne@TONxx z!sK!q^?d+~1n{fnnLZWP(r@kY=RCw+PCdG6Ys4px)^nmDR_v4eBl!2;9=U|*9 znU|z3#3c^fC3PGZ4fB^u?ALL1e|}-%AiJ<+7rGN$(7BUWhyp*iHl*-9Fm=#Ch5}xR zUALL?Baex3>ppYF|3H%0ob3c9cbQH^t0mYMuMI3RWRd*;!;!ALEe*|@O~YK2YGxNT zU-`W)A#ZcCwxN7ZWqb)az%au;_UTf*bGJ+czU9eiloSdvW0NX_ZC>Aok|EE^L;@pH z2FvU*UHYj+d^y}d;=rn~&-!jv`S%cDo@7v3ez$( zpMeGedg*Yzu2R#HyQEBtx0RL2f$J|`?@}R6p*nlkrBzQ0)CL3~$akVKH^fVwvG!1M zAm>`3RCXz6&H8Who3zR%X&vBQP%^R)yE`5rgM+6~X^laVhjWO4wcKlA$ZDZ;Aj2l7 zX0VESlYF6SgD-phY_3mkvELRRYG~8Ok$eYn_9qa%fJBKf@_FeBJK@QoWHb`0R;C`I z=$VDRKlGfJi#kR?wABCS)I~q;qxd}dT_riq9l84b^#0s*ttO8|XuBW!X9~GK(&SM( zkBoDX0Q6~R)t!WZKRvibgAIsx<#+LU^S3U`IIW$(+9s+#3yuO0mBv0v3`(DAAc`*P zkcjM84uz2he@m`-r!PLfHqBt3=j!Ixo^PfZealP;MqgxY43;>MT)g;4nftk`IK?H( zdFKWIESu~FNHLA&t^{62;Cs6?P-unYZKQw}fE$Ro^^1{a6cjG|ye?UU0uwfz>m4Hf z9d3V7BU|y(5SdiktPM+PbD_aA1^!1rj=M-|lNHa}t8nJo2$_7vdlo0EcZMaR^!@~1 zU?Q=iYx4Mz!8iO3!dMCQ5#;0SORaBP`kX|4WgOI}v}y+J9Hs^1ICA_zO*k|@O zw>HmNsYypB`r2TJ0%iu+i|bk%7#Qii7|GJ!M?`v?yiZFU$n#(=ATzJ4tGyAtwSd>6 z92wv3v*7bUgH`{~{SNJ4?HToN-W->emA%NRcNPqDw+wb6Umrx3IQS-IN^OelD|yBI z!F2rf=|I^PmybGjwXx(J%S#xa8;Nv1dJePAek+w)6U}iqG}@$s_yl@dZ6#J8bDz}E z3gxDFBuR3O?$o7=GVk%P37RURMS6r?qnXYt(+_RV=BNn?ZcZ1{d=g2uN;5cj_G}r1 zL70>q|13#faH;IrI;mcoT1m&CJ0@*>g;^#uoafFvV?0)L&{H_T?8 z2bLZfvaV?F|iLRynGk zp$KQna)aGw<*PS(?L-}14zIw$-js&SG=+$WNLzb5j9+v>)YjI5f6Zy zb~@7l+qbo|LwxCyxR%y6QZHAKBJ5>4cw$MW8Q#tQ*?6?ES*KXVeypwX1d#}lbZpdc zu7h#XT$tHW8ycH_r#V)E@$s4CPwBrkHS-K^nm^Y+KrE2ju#h4-`&z~$61n%gdxk#T zkVCk8c_po=4#{uNp7SOyppg;#Qqzb4JP$y0zAU`uela{|fF~~I4kUf*UO$G|Nnwy&qd(vOQKTAk5 zHhk@n-@#J{|9vCKRX`blaiR)L8lW?V4=k%1IXU!X?RVm$bFykt5RkQiH5#B#z}tQU zeL*QKQw$lgUapn-(+kkNyf)^@KP$)YJ@-bEgbY#WJzKqDhpCfnxQbE`j%vY%7u5`? zCTugOFo#4mX&KkXX2*V5X^TP|ZfYz)@R=8=_Ei!&8tAd2x$E=9Il~xP>mZbxdq6s% z@;>kb9Q<;ls>X9$XPc+98fk=D*Ipj2g7PB2KH>0~9P%)GzEVX+#oA=0tbEgvqj0gO zFW!PN;X9o*9c}Ko9tzM6E{Py-iu(r#D@=53cj8!P9DR!;6&;uE?5_l)FTynLM;cIX zWE=MS!_{(_kBfoate{=&>q`V;F@U{5@DGrXl8Q=5c&Zwxq{yElAUH`tPyy#XK-idU zjxexs%t=9FRx@<5Nl^2v@9%9p!kA~k_sc(Ge2J;3pxFo{8;hN_Y5s_=v?hN-$?Jko z_4W+8l#YZ1@iZ;)Ergm9>8Hh;(T*LzLxjh+#Cps-*DaaoiL7FIeR^PzAvgc&*|NpS z{ZwhT!rgq1%f<+mc;gq?AM3~6PLTK!A1U(_dbovI+}BxCJtx2YphV6*e%QiczGeF5 zF52>DDYpU!7cMLJhk8Bp@aQL)M#LlYOMQ0A$NWL)h?sVTTQ-$jC^-cRzGJoJdZdB>J@ZVbF)L>I!Aa0o)ITZOd9{yaV5l zdY~|jIzLU$=?O`zi&NXAMQq7K7CMs=UI>8ebgS?;vB}UNoTCi zc)-@G3{mvU;x?Xl2O5X*myO!qoWSn3*JHxM+Y{_`R(1Nr!?)7#X^s!)Lwib?pq#Ut#c0jy0s=1Tr?#S9J++S?z1~LgU1To-9rcan}VQ408QH= z>C%RC2YJ9|fg->JSS)cdvEf{d@tEI3YTR)GE-+LUg3|*KrQnb_94w1@=-Ve$8XNlt zD!Wq>6-!w=Wd=-mw|1yK014N!VRv7)eT- zGyZj0yaG8U)^+^Fr{fl|(d%mPfyEZuGW;+2&ZnA{Q#&MuJk3=A>3 z-XKWZftm2|${fKmoyL1gntd<`#H|(~U6P!1aL%nvR*-8(i=TUSr_6z&SHO z`G$M+5ZF^3S_5><3h<0=$7rB1Ff)@KTmn*%TjA=tO5p{P8cni#Yj>6(%4TLw4}Ly@ z5K%3z{ZxL}KF?5pZFV4&u9rbZ)^g--%KXn{NxOo1GS$Wdo;yvTS8%$9sO%~vg!81N z?2cQeaDD@LyVj|{a0=rjHLwP*&2)OflW6;^=ksoDLqkk)akzq-ohu}q_B<0L0u+Eh zt2Ef8JCR0$x4}1!Qx#>Rgb~GSZIVFtpCcnvpz{H%$z)3ukxNt*q&+kI$98?fKuLoz zb2RWI7D!ZJ;CU_KbO!m9uVzRb7KO42!8A}3_GMh_rXlzK_Y{f@?C!D0in2#L1=Lw~TAT3X&DwALy2{x^AaHTL6gAWir}L24j`~swh=Q$xjg1Y* zBJ}hqO6;??Dk34B#chaoEi5b$x`c(P1kQp-5l+sLG&5rZ2?oxNf;%!eI0(@cBn|^A z)W)0=L~=;9UKwg|6ZxP83ye}0Fy?kc}WE`+;E+$~1$2DJ?jfsxkKLEWUqt}qD z6uR4%S1BU|R@W;%k|~A5ebEPz+Cz?V+TNL-r;Z8=6*M(?wXK*Vq^$IQtw0K7gmj0l zwzgkXR13UN-Sz|KdE85*4xE9ws*ixR3m{&p#GXq=X#Hu)i9QfSa(G5JkZ=}HwUx88 z@T*s^I(H2Fvg=Zpx!6L##ut{9lo-rSEiSfP^%X3Kq6rK+_@MUSupI)V>rCiCC$ABL zeOv8eKScj%2|`0^-e5i4Z)gg;aR63=CLuwW`u1fMA;B^ASt1d{@YKkQ@GofDUoPD} z>ke>8fD8j{r^mZ@vB}BrVEh#@yp^E&fw~g|&KAVlTyFrh?sAKj(ITLXwzap<1h_8h zORYM!45!P(G#Nj51)`@nBtA-5dZu;2Wq2TR@fBf}4&lj8P<3!(=)P`8B=w z`Zk)i&}e2xVt2AhyrD(6_5iDjHBqDfR$3~m6xP?r8VWo-0@5?DKzBi3;2{^ona;00 zkE55NL_&Zw`~~QIOsa(+AR^tod2df(wgd0Z#S^1>GBI z*1tTe5jj*C_z7ZTd3(S;7{nqO=Q23FgDw*c?`Ex+ZT&k7OY+1eB$U#Dc__dgNP0K z!<~sHY!7W`FhV$N&YOI9wckuFz_T-)yQ|aenA+#W!?TI!{V=w4ZE*-3!8;v%bq5Aw z;^HsB7EoDPxdeS90{oOev!S18+K7Ky znFeJd7&^Mpi+;?11;Lq1^rtJ7Z5Ry%jH(d%TCP>akV znh^a2AHFTR?~MM#qAT;1RBwO2OYNE2k1`!Cp&V|YAstDFX)EBK_3noDIomOBo*8B_ z{csq#kJIjP=dc4t0{4bLa0qpJi$iD;@U~R9z?mwsfSD1%iD|Nj;-U!x#@+?gRRX2$ zy$`bE1Wb6i3dII)PQj~V__B{5KQ>uKrg^TM5{_8EVa7bFsIFA@@r41e!UrtPn~QlIlfPv(-E6v)Z{|*UakeDRJOIaEG0N$$xO~0-bTf^hA9iY`Nj-={krS zGurzd9Zz9Ry>z5wV4zsF9hh{Llp}jC_bFHT z?pjwVV763>20i0)T$3Lui5?`!G6^0NJUMsnkK5uePL?FB>5O)hTq?3+I)Q(xXQx~q z;rQAqqc2&iN9YJ5smZfbhmMx6JcRX{;PIp;iGveZgLfvFa3jh=>kzg&O?N5pYa+~1 zMp=2!rUNqQU*9n~O+r33!icJjRR)LSh1G^Ikwi7h>4Sk}mhPn`^)!0K6C7E=6Bde0CIs@7^ z-YxPLUmbE@VzznEf1>Q0H~uv5=NPt{5|YIfcHNdQk#iwPt|!hy8}tj>WuK2^&$OR% z!AIJ^AOE6-S9#{vjwNO5xdZ9_+uEb315fO;$^5p}!}j)V=HFoibhwja0s;aq-BQ0@ zf_gOtG#JnzeGm~O!PpSU;|No48-ao511re0sjptSMkwipT>bX9aB3%5Q_~y30W z%(0@HLfB%umUYcrOf$AIWQS?}JW76=h z=$nfcltZZS3ojTIe-xdCRla*}ks{6{wc9m|?D`F+Z)h*HSqnN#WJ)G#sz1@9T1b-7 z%WQsfLO$-%VGz)Hl0dQ!lPSQh%VDw(pTf6xI2=inZ@?_?A|AyXmn9kXCH%PyR*aQTsA*b=s8 zXl#7+4J_v|OM$YPPe}z9wGpS0Y~k_ykLnZyzSVFDmrg3qtv5^=vm-a&Mx}fUJ_I}4 zot^&!HGn7N2qaCMQv_pNlyc|K!0L*I27>>SoIx;=5>!=HRfoWV_b*q0ls_6MZmT;r zgI)kDX|)x2G@@Y`fgP+SAeeCCsqV*4Hp9lT*8MD@lcoDTl*rRK;gW|I zL?1Z~%12rVj|GaarH!J$k|xCEoXE-wZ9EhDA?SmwnzGvLAj>p&Dg|cBh=G;acTaWO zQFzm0f!Zc-U~E1IKny9X+VhEalEa(9<8LpZW(F+0}7ZbdNrFpYti zDa8H5ABZ4J#k(V)?#85bYMoG59^?dOaP|HA6^T=likEVUAziq=pxPSfAL^`$;Q%7< z$S{sq**OFo<8a`%#ZK%Q^~F-`nZn15gIwL0eZ5s{8$(;36)jH6qbFGJvvfmEhD+gX z*UeXfvH!oJ(>c%P@S~UiqDSO|Qc~sM{ARx)e<}g%;dwYQQapf?%JUE)T)>U<;zx#;16&aG3|2GI!14Bl_sHlG_q3-S#yn>QyPo9kY;y55M zQC5$5*!zVACL}QYjTyl7OGV}L^UdA+qk)6bzYN~VB$@H@qFeV$=pL~SaSoFVoXOF2`e0B!^D!5YXw*b6{itLRL;mSZLKxJVo zvL2BbgHbU5MJOD(&dRC_=c;AvwI21VDhFuHYrpn|Z3AaL4d*=v7APPAa2`+CgIs+) zhCR0-7k~k|5`5M`TGVfq3}ow*Kpl_(a^`V-`~aAVXp}cl4TaZTI9vene_|u`&B2#m z2lmX1=*G_W~TXYy}g6*uU+Z+4---!To&}1a|baou^zC~(BnW30RJjXLj->yxf7UGs=zgVu{0S)Vm zM)1w_N6fu<&w2b$7BLL#n2llC7AfZGTGaLoO{-lYIG>{(4tQ?TTz*U?G~m~H^B+aP2hq(0#E?BhvoP z>stGqwa(cRGtb=j=X0fIqA3ct5sUH$%QvAFqht*%-nwVci_&cL1jY_oT)g-oarIGT zWq+%VS^@6*GiLS_gL*HtN(0RD5QQk`)~#ElH7qRBP{qLZnUR&HZYi5u;0)CkUT^u% z24iGbf&V74(xy8LscH003cbx{5|T5*lk{uWvA&(%F#Ts~4ds80ZMQd#%VejQs)$5l zBMBTyNNZJD{G=?KsHaH+Hz&oI&PCRzQa<96wEnL^zhaYP;j$m| zsAJ7X#u~ITGBY=i6T(qs;4q3g9l<^NT042|Mzj+ANoh)z>i0~^0X$Pnfr<{F_Otk% zex5bAASy+rSWAlviSXlqXU2}A1H7GB9_70l@|?vm)`8v8JQR!r>BWVl?-!C<%gf_R zN4fL1V)~Ep%O^lG^j*!&%*0S?A5QF+edtlH9W%%W7s%!Aym!^5nkregnP!xW*ZO{& z_AUj_PkZ#Q2dPDu)~4OKox372BsQCE&?&WAfb^%xf|%B1omrVkA>Y7&BIVY0&G#dm z%(F8Itm$LzlM_|TgOKRC@Az#1@@K+2_s*~Rp=ZO_ zjbd~o1m=*emzI|9LFo;AspuGy3o6$(&KXr8p|8&Af}C70AFd;*e}GAj1x`@j;a37l z=Z5AAFkbj7V7yKuV}m>U$AZ~e|0oTFwe&Je+S$D_3l9z^0#=a%$xF$6^$L5-g|C0) ziVQX@Pjy|s^p9Dww#nUlgN4vI?_=&;)gSZrk`@JzIiEK+8dk4U(tz2BIb-INVf4!x8rk14+o-i-+8Pp}f%8J8N zw=G)`5K}>Ar8gc`nQ);+uX7!zqjz$g=m~{O0x=b5L-{?4;1ue3yB{c3&?;5kfPFL} zxFh`7)&pw9kOY{LM0_p0lLQSyzZF@o6B83cMTvSf>^OU*p?`))O!G^zFIew)x&oo) zh(RL+a$d}WnlqjsH#$4|=Vq=;_6wel9ME~6!b#l1e(e!EIrh4zb{Nq8(4`#n)0RFw z)2Km`xf=EE%n4q5#6@1b^+CBDvBqmJ!xxj^q9`4IoxK=)iy zT>RL)3P5{r`*N}Y3 zHOpI={`2C5Ydst5ywzk)l@8!~uqrxt@!~?F_z;3bEAL;+C|__zn5Z6oLzap2O|Fkw z*5!P~T3VY9S!jGXL~_JnuZbC*0a}aZU*dk`=yhOmr-ZuFu!Ra z@RX(hPKw3#znhIP&{Q9dN7M&UWJW&y2ZO_azzH2KTvFM1%tqIR@fxFMy$p65h&-ST zVB|Ms#Qm}8)AI5Y@fJd&lYCtEP%n||ah51!US|OI*z%$AuU|hYTONT!>w*AmX8}6+Kd3}>5 zE1CMie4d`tT4!SE?5-4{q_A40M0Syw{ALqdpGDX~Ml5?mSBv{7z9Gww_iz-4|_TYD&vHk~)R@hPti=n%wTNWvcBh09M1 zzbudTN)ndEuO`mZTTnc=6NwMbv%?W(VS;`*3c$f(qA1i(PJ~&5gaRjApwLEVb>&^f zxsp9txP?Hu0KtR%IvPg+2Dq)xcXA-FHmJRqpZkh(S<##pKqchWr_UWX6dx)2r;5K7 zPiTrAQU5@@SGh+^dhyLRMv3dkcxB>c`tCNKj}mc|7s^*$y&H&>qO2k|Rn7Y3@l|65 z`pJhh#ut(>Rw;z~-+gd*A2ojCJc@U>;dw=r31+AwB*EIkMoVO~l4w))c}tfsM|#vV zB%Cz)h)`E+R1xZ+*VGZH) za6W^WDb{2H<%hr%5Pod^QR|<4)B zspX5mHj9aFb3OQ$Fd@s*_(_Z~hG9v0GZpl2333bvH-e*kJuiKewT&Vv<8z1#4+PN zwV25gM8w1*kmtkU^}e#Q8)whS8##DQ6;+?d4~Le^x4#E}WmO&uYzj$-`iAzO-FADd zAFY3Xm0v!`?2^rfYa43gJw;SRQ{Lw0%rW+NPf??x*N34X-<4rKG&x{_Z{NO+6U_}# z5y+ibgNbGVK~lp1Zg6wqeot|j-=H=iWaH3l)Hgf_xd|BM5X9&zs;XeFu7czvv_J;^ zJw3~h0t)k=9xF5P<|sD->2$|xJN1^Cs?Q}C1Tb1lnUGpIDJuJObyFfrgyoE~v0R)B z{vsf(-fS%^8+>RHTnrieDo@SfaT5D#_YU*J;Dik`A7d6IypQqzfO-1E1#)(JpTIy# z%woMPO{ggcKPi|JpDG**?w zk4`i2&wVLf_iTT);&Y25)WZ=KQx9Zz2zNlFhfXD}A=##90dpL3q~Dv15Z9xyL|X@2Q%@;EB@r@7?a*dx9nn z_&t!qu=@2Zb=nqLl#|f4nOR#e+2_1O9G^00+5pWAi{ye&ot@$;D$H`vWv=0LMGT4W z{reYsXU1MN&D0y<2>gR}D)ZKZzrmEwiw;KrCW&G7v-8Ok2^348;c@Dxe&bDAAKZH= z#>0BtOy_6|DeY|Q+o`JFWvf@PZ{PKnBJ#%u`MUh^@o@oB$6tPE`Tue8c3IR?kdG{& zdt|#n*1KG{Ten<4*q%>Qn_E8?P#*$ zg#=9uT>tr>+voNW-_Y9_5fsme9p z&SL>qYL^Fw*%~bt#+2CAiq5Le=xwP>YpYMQruLq19wz+6fHH~#E`06U*9u#1)9^x0QC9x;qfh3*DYiz zzOFo&ryvj9%%}ecw&a)NN2AODauF$n2%`NEdx;0IF}@7xL0}+{K^XGAV5ym42p4XM-PgePvo7QD~( zZy)GfAnSmVK*Vl@bl}W4q?vs9mIvW-r;~J)iM~6TAR&j#ct(2b8E{zRritmJ*~vdp z{P8_j*3DpT(Sr92>Q*Y}H%97sjt#kgb>JP`v2l`ndm+yq5Ms=&%9*nzeSR1!KHFcM zRlYS|N$267usQk-wnzEj1rS!aaQcR3Wqr00|lNe0LPp%ruz zXJ00={_dcM#^ZtG1X%_JVv0SrX-pAfvgkK4LEWO>6ZV~gqxmm|#Kbpk+Qe%6Wi6Hp zH8PEV{sp(le71gcAa|Mz(F{5mID*Rk<%smQZ{Ku@v?(ID7uQrT-#NYPHv0h)NIr@y zDztIYo;-8}{td#C2oVi2Sm2$&0)4Qs0Fl3zy$Y~syaf^zgeL=o*~w{4ZVgC0DJdy| zT;V?Qae4{|_4O(D=X7a3`k~2i1L(`CRXEu01Psz-{_jyK7v_Vi%wlm_Yy@k*=g(!c8dg zRD!W{Zmc4v~+n(b6Tb*@8&jp_v5Q!34pZBo1Ax>-W z;d8I+Hl;P?I2lb#1&6$q-R<;QEO&-sN@852QrSMbz$UfZx&&e&<;*rO7QVFk8~AX2 z(N2tdT>vLrEbCQKeK-U`ofnbCS*WM!+e;{Uu@lk#7#{BQ5~e)*R~b(S0R`z+-5~By z_*&p0Uv(68t-tO1_3HtH`VL-;AUv`V5FkI8dM_*Mkp1T^2Q?SMa~AMYVAb+O;wrX1z`lio8?Ka`zD<_osN$0?P7FA6#9d z!=v-6ho_@3iaZ*k`OQ77+xdux6}Rl}Lx-wQEu2NT4-mCP7|Dr=9o&n|v15O>4i^-1 z#STsNs?)MAM?kTnYPmYKJ-eSTr^D~pd^O29KVOjmFyDhl7CA%}I3tm?Sm`+kM`#rE z$Or^r9G@o$qba*&dO~vs;l(P=7#kWo)WlBAU7vr>T^^U~#r*8=xEE|Xy;7RDv=I2O z3&eY8DVs?`o;?z3msyF$fU_pubYeJvG-dis1;u}0hftQFVkVb};`0AOlyc8cb=i$u zvk$Dq?LA>VBv3eEJ(gGMp;(uqC--RRz1zH^Q2#>r`cdo%(D|Ff7xN@CQm;081H?f9 zBXKI>|LJH(2JY2EjeHS}hF!AG(NuR{r1t*^wkcwM5}*xswV zuK9-FFCTIZ9Gom-eA9CMus+2E1})rY1d{_En1BgfuPr-Mb(ng&L^?AQ zK{V*!xn$64f~=~}8n*T9XSeR%yX?ggM@n}$fgV)}pcn^QMF$5bt`0=Nq9}I-Cde56 z^a9P7=4XVsxyhH=5Y9mYiq(@MX5X20UkW#X-8F6PI-$08SKrju_&ZZ3y5*<&291v6 zm-JBLyJ64Xl5c&wU0%=H+;YLAC$UbnihtlvL+|X4X^+Yds_5aw*3rB6rli14PEgF* zuH$m<*^OH{I99lzjmdy%ew`4=6WZ0|e(#<~HPeX`Cx|p~kQ0z;-U9B`?l8Ox`gaEa zBPUgjeD8ev@(4#mR>W2EQiGG^BY&YP!q zn@c@cjxN*EGkVi!$ZjFd9Au6k zj`!&e7*yn9u|mH?;0AJG2b%c*YV^htB9J5GpNoC#DkgW83{yJH*s$Lm#f?syAk(I} zff*ilo;?DV@loz61*VpNlU;dQF)%Pd6Ilr-qHAE_CR~4es;a~SFC|@$!vnYu(P!n_ zL?{Mc!t^Gge*vOM#9o6}9r@K#=-@!=#*Rzr#;X2_P|D$SK4{r<5n4LX$BY1iNSH!? zD%%~o{Zo+Q9tq~fs;K_lzaUwWRg}*iZ^tH^1t(iitK_JBpU{=0c<1JoGE+n;EAMW3 z9q>|FNz6{M&n(@_nhXul=SYGbgS6J z(3H%n{YiG7z8GPb7rG^OFOzI!U)d^UBHLw{-kBFJ+~ za~c|M7ZRp6xo1bF4P1Av9swhZCb4piU@S>aQ2OZ#JPjAG`&D!D@~@o;q8KJIG7LMP zKWnNvOs5ak1miG(gz0<35C%Sv-^Tai?%kz;N$-S)ZXt*z?2^P_ zk0=ZR^fD?2gvK|_ebr>)@p)(;BgXLSwD7vtuFj!2& zpQH!lAzWYkRg@+RPXeL9SV=gK&>2gl_dwo!2G>p_D0Con&mr^2xj58fQAud+5OXF0 z@f{i;GWD}?$wKRLrQ_{wfSW|{I;^Cnn1eyZrx-W`0rFrG4!~me0AS$oYkG!@&FXON zMmUabMur)Ir%}4i`$DyLj-1*$CBchRj-;~Z)oYIQ?6)v+tZ&$nP$!7xHEAp{m6T$e zu}Vv9vq8!=qf&yBB` zlk#m(I`_qB#jR%F&qpXCwY8rOn#d{J;{y$fs{=VD+Au&69RDUY zn>Q3H(oy_DLo=H26Q;4+u?dJn=^=fAL&Csev0A!qNA<@=n;14_FUawjPPfY0AZ4%u zJ~9vcOQ$c{EVgO#f4XGpGKM$$$<@xsXiUxSL-!`qZ#m~zH@&T>w;FOaaz?nl%S`y> z$%qm8?<>^>!@k|nRS{8bJY?ivm1b1IzuH8&Ea=NYiDxJ8M+8)+H8w}bS^PJhKe2dP zGxbt%g8c%LLgIk1yAgz^g;t^_G$dT;%ImvxyFpfD3aFW5HDK=H^CxqA;P7epE|wuidcW z1b{En|MFnuH#bj5_mc=Ze;qQ69}F_)8m(-m;lazPH$#xy{!^Y$70QJ7vMAPlY!jg&aKNom>%;s(12eAZda9q6-cw zjCod0E$hrzoUlD{GQ#J_8slY|i(Evj9Bp=wu-su^S%AqY$IX6of-Wg;DrLc^H-W4> z@pMD{6dhahAG|(=kv!%we>Htc?+8JT6l6HyV+mP7Tz?Up^G*mm5X+=$>4oR*qP=Q4 zRF=$jZ2;k8ymCT*$EqobkmMh@|07TsmN9(DuYa#D$f!q(nM{PJQEUfA?b5o!pKLu) zsXqPo|Df|9Wn?tOQ-LR(zkFGL=OA~1btW8-q!3;`&3c~6D6f3s`{DPczh_=3<$BJ$jn3kj6E8 zGRs-VxgtWeGE=TQI#z37H|f_e-gWU`)-3Z2O2i_m&18KpZNeVM74$KhVQMDl@)|Vf zeYZ4GK-u6cQ;Z>TI}7fb%$mdJwzFY)pz#VKGj{9aF1r=GOEnWVH|UM5I=-)1>= zoX}T4n&yRJwna%1B5Jmb<2oQz|Cfl zLCknjhP7?u7VIsh>wh3R!P2X0UWu8I)K?zKaxge1@3h%i@g*n|mAfbV&Hf3+w`8~c z_%RIOGTf0k&XU%V*ZV|3x-#dm*= zDhI%C!7D_`9+rVdq;~6{ZFjNU%UrlnP16}@>wFSBOrwc0y80DYE!=QU?ofdi(`P2# z;6GidK}+iP7pNN5^DCBKJfrOF#(w8SYCz*|>Zz}S4A+#mpJZ~ot)qNQLQ77uj6Qbh z_9x6;<4e?^v#(iPP&i_n*P3BlJ}R2iR_{T}?h2_t0XGt1Y=G@(RES1sgm6s90*X`H86Fm9 z)0bF8X#DqZa1e4W2o5fO-^9%9;qERK7v&be%hYD8tC(d9(ZJ9%X^r}Tx*Ptg4J0*OqqJla1A(e03GlwiQoRw}` zbcNR^Q`E2e^Mz8W_r1)W7%zylETG17f6`xI_QqNQ*l)8+uEXZYs#Dlo2z?y38gP&n z^{Uo{PT|qenYQZwda_`ZG6mmfcL;T90oC>aXq|N z$FdfEVX5HB^GbB5yE5cfqEK1o=wMx~CfjLPcov*s9 z>YGUmb{A?pOUBC;qkWegS50JO*q#j?JMKU1<&_tHE2kw0O8Y7tk$6z@S8!jX?r(`+ zcYNJakEKt$pFT`m{WS!kQj7<#kT5S?gAyuj^?YXF7cWJnbC*)tr_U{>>la>7e?C&} zX>O`X`$HmXsR>CsT9DtESy*Vjy|pZD^*o{^5&u{w%0$9AfKcWM-D)_2IGTy=Dg-2g+^>Tz4Lxpi7)(Dh9z>|nCd9BBfKx&^0(>S zd_{uoPrpsw@2p3IM>#w%sc!D>kx*`=t?mrC_P!TsX*a^d!zal&N89QfSkuF!r~!4; z*?Aif+7kHSfszA1UI9av`+pw`#hf5vGQUF5?*{8aXe`P&SP_tFn3R^<+dMR-!bcdt z<5k_0lamW3PoPlLLY4i}mL#PHvkuGh{??LE{tly_9c6aooe$aE65U^>8BJ&R@9#_T zX}FU((@AmuG5TIzEBZjK?J8wT-ZSd4@&WSAoAl^Ds^t-wyDws|41?-P-Ha3nw1gyC zGN#8WcT5rcJbuW~L)Oj5jP!(G^h*a%YYWYM*PuA}IE7dll{$OR1ipJA!PFqI_3GtQ z;a!t)l=dqJz^I^Gu*h&;;9JZ|uCV^dfK)on_`~WaPAo!qdj~jT4s1k(ypAZv2|8<; zXL0dMH$3h-T%qSx^#Wm-A1vdk`~bBvfP5mw4hvq_7-s(2vGlwuKs`w0{055<&iIX; zou5CKkx?QdgRpTDQ2#>Y_&%DTK8v5z0zBGEvS0>jk}fohmE@tr&}sa22uV8$>kvZX zQuc`&)RFtAKBhSt)ek`LNw6+N9PNwqJBY;>L}FZHE_nH7>^yL84@Pmr{1 z+cLwM=96u`W2|PZW>BSsxo3*?=cQykkd2smaM=5>nwkA=+1ZI@id<@mO5L4RY<`UX z#hc{vwpQ?XDYmF<3_QsRdoL>Kp}Nxj#zwlJP8E=7wtar>qNlyxM0D3y-Ax66J$i8UWX8_5IhPZnGk9G8Xj2X_QX;aY}^ZQ;6W^E zUM?D=NbZ81fE~T#h}$932&!_SHVeQz1W}wP6QAbLmlB1aaXXN+U^FNFbi(>&R#;)_ z!Ymd)#(nVMS{LkOpk$AOP$$S3xS%Y$&c=L>F>*AB_vY)ZzfOgM<{ct78nSJ90Ipsw zeXtkwnzAJ|-rR_CFUMVEY*oM6s3l*7NmJBb3TF%Fx_U`|*2liGI~;C0(BW9xS@?%| zo?d_#k!D!iC2B1SfRU#TqW@vTLdnMp9gc1YVo zxit0{P3IW=yN9%_5t%TK6<& zD1)STL7I0D7T}B>;Uk~G6BM>ZSUs5pG+){;O3^Huf>yV}|{1 zvb)*f4BIOtFVUIiskg4-*4y>ByF~w7`zP-*!v#ml-_)|%rbKUUVkrD}^{Vq*r?+Y= z^78`4NRDdo&|TcFF{rVzH)A5>hiP9viPx}YO=Xryuj!(FUs)z+>7U|L&4UlzgP>->Ng+^W0ziq$;rIvxu~?DD(~S?* z_C@uXZ*B}tTE@((J30|lq8%Ao^*LkY!plr=ozRH;JrCnV_HuJRKk(e={U$ECFhvjR z-6j@U){-V?DgsUS((V@sDGvO|Qwyw6{T%t2ZS5hETMCYsTR*7eeW45(i&|Z`j9oXK zIyR5Mrw0hNE1-cw6Oo5#^IHiO=fw0hk&N(YXmuNujB0k@cj1XaDG^IA=Lb-msqJt2 z>opH3In|H6*V*yF-(OxZw+VUZ6;Di%5>eaBzI*pDHa&&rF@!&(yv43OQA|Dk*@SUG z1X;aibj9-Jgv{HpCBqk$gRD*y8bq}M`0(CctJ|-rhvkG#j&Gtp`_qxWPqnYyI=$T| zLN)hZ(!G5}sjBVjPF&2b%w*vQ948c&4w^2CV>LVxK_ffmWiL$NQ7SCuPE+WdbrwuH zUO8VgndmRHyN4W*0Y-h>&YeW#ki`?$*MQRTtANkFK!)w37xr#rQ6h*(m-lmb_mYcF z3LquQ`jK_?;!xY0H*_z~KH1_aMzv0SHX;r30hLum6${F>uA(^hPgFO{57wqQ89}KN zcR7zA5~jaZzCgqX%pzSPCp?@G|Ly4Y+m8?KBkG4S`Sq0o-wdZN4VxKjb1jaf6A%;V z3-8x!$k?V+Q(2vDKU|u-S;uV1^leH0RFe2AW+syVY15lkLsH&J_YWzEyjosa_i&}k zfdp17IqUi+F&DqA^@{hL><~Qbc4J?sL6f>;Ft6S^5`JyVDUUgBwne7rfi3s~-oQda zx(r@~AlMKkU~xY=BO?eO;}2N*ro0uNdJ)(lmfRB%<09MQ3d&j!3oD9#NQRP(c<*pI zV!JJe9WKVhr0U5c1gODtE(cY+p5C=f{!M4vNd(q~)!7HUIN&Zq^9ET}s!(o7UHToI z$wae<7Km`7vIrM$GLk4PM5d?K9X{fdAHmXvk8u4<(VSE-2d7&AP{K}&<=1Ui{(j&I z{aD2q={ifZzmY|n+4la0g2EOPc4PG|0%N&CUWJSgV}^T zpIbDY1SYM+1WoVMw1=|`@T9AaD~5)QwZ|&+cp1V2W48CibN7k*YG?V)>NT@HM6Jco z7+vywUJr%W@|EL3RIp>4HJu!~hQbnv@<;lc1D$Ep?dT7Io7e^KG7-TCb%+3mcBVMt zWdMO4s;Mj+^vXPHJARgu@R3NAuQ&bS(p0D$%; z&O&<|n>EN6C7MvNeV_~qL{&+2>c1=wX|;p3#6(gQGHOtbaAnx>CugSzfTdo8@&r;9 z#pZN4@F3x-|8DH)GQS$;YuSS3`i zb~e^>cE%P)<@iQ5C8bN;*qWMWdgtJ9Ut!<>+A4;A+bZe;Bi6i>K_3tPLRU3YdWf=! zr~$$Geh?SimClVL8Hq54j8(F~uNejGhB-8#E$-^B2&Qnu@TNR+`pg+k;;WHi zx~=IcZB2yO`S;Xb`+ZaaP4fM-K9>2wt1OHmTJ!w}ofxt#9jk zrRCGB$Tkr1_wRD|Zn?on_hL_M2b@MrQt?gZ*6r=);h>J#piD&=YgauW;6$6PeE^M$ z%gVk0Jdci8`qfJwrwSr=04YCz^5n*2an~dyGQurK`c_Y7gT6-#$R}yPdM@NRT|WN) zMAyZ5i-osse2jGt&SqE<79PceLDU)`&Q?eIFx64#F=_5`qWzZ7LWfrqK7Ik>vka3Hqa#}1k{)O9njIV$ z%*!5=?S9Mr}$Cr|#3ZizN+-0sy-F9{Zd($eTqDQxHnwq|xp{a){ zmhILO?f6y~X=6R|?Ak!U#$Lq-iav*UZaYeioxiM7+RD&c{>XYsM^o7bmm!X?_%ioL zPjAE*#8~uppnY1ToMNERn`+xSZpo@Tw1*B;dj(so-Gfx`xUZ8f-6bj!B?7~_+XQ$5 z7q4EWE0DrM-^K9yv9EZlh4I6rV7B|tpJewszioVMJY~`?Sa@k%Uxuxz5^jp7Y?&NxyQ><=9 zz1*hqOgfgCsM$> zui&~X^eA(Q%Sljw-|+*c;?CM$6UFIMbmWt>N`imKKgZy3v`zja2Pt+?NC;0 zdFztC_+l{kF813yB3LvGdz3KS#NA`lccRTL)Dp4sCQ&93tDw8kbjKpA?ruIX~Sm2lf>}dwdy4OVy&-a`P{JC zUAQ=p9PWK1RIrwD?J2+4rRqyZ?okS+9}n=@3|{e&Icde+;wj0&u$YTcmom_tU+<7D zrXi+5zTMIOp3Oy+dvx2ueZC132TISB9-gQ=#!Blma}b*TRMY61AHm8_b9Hz$WISb} zM!i!Nda`Ew(?uluO)Ga+hYuBBNYur-xRIb$+4vbsd)8 z!2XJwx#js-_*;PtbB1v-%e;ah*7G8#Jf-6f)u)r4-&?ae6g7NIwxYB_UmczQkn zLNl({E~pQ7bl4_RPDyZ~QIas!BC@?s*;FjuqFW}l{a8Op+pV~_VOR>TwCro}#Uqtb3N^^m%3dULM+;Z=QGKI+BlY^jX! zQnrViTt-7?8!2;%MfvFo^;ZrZhj2IASP$_>3{$>IV`t;~s{Z7Y1RZovHr5G-dC{M2 z=oIh8`>Y8$if#O$)xqq~W6Rn7+-`I(B3-wMrQcmG^Fu9tyy3_-o}ye)?a^EZ`w4UX z_PvjWDrR!r#}@=xe~iHJa;@WiP&c19V-}+*EA=40pi-H|l=}0@q1)VMW9Dgl^t7aB z=8x9VDBvmFSm_`Gg6CKqJ01XeB5fG{JV;23Av8BR83x5o40W|JEi-2H6M5FYcJzVj zJ`Ro;bB9!qa?dgoqwk?je}wPV%#Ywd@Gbn9P3mBh9W@3wd^EFq%u1hBCnweTwn2s~ z3FN7q_Ag;28I!N%g}qIDxc$6jJ{K46xVrmV@<>P2k*V3p>u!A)3|5xk43WbQJrgEt+zeoRFj8! zc-BW&-HnK7UsXxGCLzEf_-D-M={o4Hv$kf|&DIKrI@LLZg$BF7(S2P`J~Y_!RNSw0 zNkPb2`P>Jl*DarFblwS*7LyvL_`3}x&yDuWBK>?9kF6>e3z3a{=KobQJ|KtA)a1LD z_>LvBep75hUVS#@6F4`%uWP)`<*RCHZvA=Mvt8N$g*Cq7V2)>_p!4oHR{az7u8aF@ zES9LzsU5Z#lDq!u?r>4%dgKY+a98x2W%}-i?X^MCQSqNp(UpvA9M6wZ%HCP}J%EX1R!od3@=J|zQEbnpa5*jOr z%LvIoAia=gLT?HA)m|>HE~pRTBSV~5dQ0q;k zh<@tpbI2dAm;4?YZqmP#o5NdD&G8miy^IUjZ&yo2r83L}?}%XA1`m!-b!CEOp@NXd zH4MUSX*X!*rZVb+^PtNPgO&q7Y za{W+sN8;+IIld~&X3Xi1Y#L8fy=C!XF|Hzh4fa(9jh zvx)`r$c8mJ-|KAls(C8DK4!dYQ(sZ;u4&!jQ(G>JwS?gM4(_cH$d1`o@vwqNA!I?tqcoC`NSoU#=O$!x+?F3yHkh56{Mk5Ezh(aODyI0nSs2l;K`6ZeL|KUb zLd14LmTaP6XzuFn=C%!|7{FiXWW?{R)Bvy2H3sDa5#a~hZw3R4DR zZ64ZF1W$S~pSH0%3;|@<7|5ERR(W6FV@S2KA?${hvs(ruKGKL!;pb55$d8t}5oo_| zx=VJxt(Yoz79)v0BFHe;Aosu5f^q9XD?(?Gdw2H6_^UiuKUcqk);@;9Bd5&N4!+M1 zL=F>_A1n;zPQ@*(vnLNncud}!cs6L0Hu$u&*ek5bzO;pPYW&>3QjSv|XPzETXB-cp zq_EYswHUX5cxaT^e0ZEHh@5a;u@n)!IafwU2Um@K{SN;I|5#PjXj(r!8cwxQ0B z+vZ;SAt|dx-Ic+lF=y*f&$vD&>x}XhcYf|VXwq%^nD3&ura! zYv&r=pp~aZj95xpIN;+&74ZSYoIR6`Fzz*-yWPKRJok&J;CRnf|8m6h?p-DB`Muyu z?|cl{myJZpda?96tN~DjAO-L@>cUvVG8!@V!i~9(S#jbSFXQWyXq;1;J)3GDj(_hH z4?L(EZS>2W8TWGq_#jQ)uDN%=XxVR6#Eib-!(AX85`O0_w)1O&&ba&0(7wegU`$#6 zw^{!SJ7Ih@AdHU{6_kK*=PIguu}a|Sx;y(fTB#@*u?@(yr7SbCXf(OE-!5=EeBkHYPpoTsF??NQOSLa{{;)j2?nNkk z0G;3|?*N!jQpvXQMHcuEz>6W%d0+vEuv?_~K`fM*oV;Vto~0z>S?KEn%%3MeOb_>h zx6VV`J8&m|Mjag*%rjd!rs$H%B!8E8b`|5Mf;|=ku!3RAJ<*5Nk;WR`tDmh z69!GT*pi#=-`T!PL^u~$ml~u8BF0&hqkn!~qV&O-j)XH~t=6XeCy!2$x(>rRsb(@g z|N8r$skfA*f*3%fb;4A3@hEX#5(*!DFblu~g2V-ZTY#Yh`F})Q#i#K+ng{@p=V%il z4AiJEX2jkIG6P;17z$kBQNl37E|RV6s5V-$Mi~ee~#2&ta5i{Y2fe z$h#lf+<-}8!KbE{4fdPtSFT!_G4<;5$cleX)fN7@UB#S6C9@Y~6G+-i3%Sh`V@ECQ zr|w;UI5T!Sn=+_L?d)wlV#|{suqtM>$^Iuk-BBbWmb6EA?ZIb3`qQ<4%28kBNAIyoAm`E5Mzn}GSy@r9w|X97~&JvJPlMTXD~T+X<>MPt1vFa86yI* z_0Uk7r*9dSYBp{yz$W}k$Q=0ViL8Ijh#EO@^H}S4f%uB_TC`sMb0Qm|v`&X~_e$Y; zX&QJvhT#l#kYqtF7+%2uhpz8~w3ciZ{;I+RplhJK>ay@2B}4$6Y~0+pUv_4D_D^uM zOJv4e_qL_|ujg<|zFQ*4+uM7x9b6a;a_9md=c{yA@dgc24Ymp_>1ILmtErA~!vWJ; ziPX+N@V4MJBEl~{3L`}86eEJ6P0%)L3z>{Fi<^w&bhJngmliV+ttc-mxWfCXt9$WZ zxMO@!^9q?iE^cmr{g{q$8Zwf5mmG#Fc$o`sA$NnFa|i8qf8dWC1pYYt3x8A@#-~Id z8zzw;fb<9yX#YT0HPO@vahV2X7-g~Mh$SKPfkZVO^mzyXN(_3Ah+dR0)REO?Axnsg zic+XF@ih3$R9OBm+JHt@7wy&%v#XtJ32abE^<7@TY)q-m_(lq&$70CpE?iat?PeRU z^>?iD^VrzFJLB_GD|6xKn*KQG%!pwH^$}XUOvurWgw_;c6%4fxH)XCRkifq)0FaOX zBBTUKJ*2~?pGZVA5RlV?l9FXE0DfFPd^qQXf7t>mc6va_$Dl8*6d7j*qrdaWkubnk zm%GyyqybHUY4fo@Tsb3D$hFv|WH)>0z&*0`_+aa4dl64ek$R2KcTwB>OpI5Ata&$R zRAie!u!^a@IcW6`A)ieC8qI7!*YzMu44sU5dQZmh*m}gJ>U3mWo4AI?H4z8cMTW@? zbJvx`yZiqqz$PQW$Liaxdi>M^Ff`b9YqSqSfPWAQS>hnVoM-f_>byAaNy4KfA?dNl zD;G3bFYH0vjl@%~f92)B1VrKbY2gJIPdK(I6ysmFqJ;4!;^u?MtuxI#`L|n3b5Usf zd6NST{|LJbP5htayLA%ECu$H#`}-Bdj~4r4>7*UIUE9ejZuQx=4F&If=ZK zf3yZIMPVnwO(R~vtRF4oGw`}b;`y?%v4IelW=Czgld6{=mh1SvCc2hy8YNo8#XG!- zNzuJw9`pH9p^^RY7(z4Oq0#7b3sF{qVRJJ=1{N(^MC{N~F6P~EAFhSARReljB*J65 zUyb8}bBYM@C+AMx1L?PTHFI%GriCqx;B?TlXdw@!#hFGWE^Xu#gdmZj>N90@1Bb#7 z5WVJj%74J)M8y8#93o;XfyZg2nh`O-a3dzPjoIQek!;m}nK+*gYD(mk&-0qw^H$aS zzo11yiS3IVCdAm@0pJcf&FI0nmJT9F1-u>fr)(r-ro>hgeVGs^(78ZQfbXSkY>)8J z{Zl6q1-)g9ff*Mr8=_JSsvM$37*1j$*Jbthe5N@q0Dk6+TNJSXmAg$5ATd9<(N~6R zNwC~JGS8bo)6Bawa?VpSz_&QK|y))g#CCcEv{Mz zyAof;nYy#+65C4%g$*0)MmC$u)J!qD5wib>cT} zIR#Vr&(4fInkcsIF44s|zgkPP`;|BxK_nAVQ-^i&$Jm%Q=9aFV)ADfh$a_h%*N`ty zb?KY8zkeUo*7YmGqumQcouh+88ST!kTYzy3kaaJCS5>b$jgthwD#~X#70RtgHBz?M z!j`f9(4qT~Ya+I@F~cnK#FN>}1RsSB#}+{>gJWZhxAO2LpUFeh#IPBX7Eea51-pVk z1r>wup%}m}IUF?2L7vQlD_n2pkNEA@0du?W#$UTHAu2}vGSNX!f_C6tWhHqw(qFg~ z60ahRHArIHGd(__1L0Sf-AHQYZz?w;*#?)C{P%H~uaohL5~+vS?ucM0XbGdM1yc9E zGQT|_6VX-dOj~hO+nB38T(sO@{m2??@U3vJ6IBEi(YC)nvtt*Y3-|onl1LXMXu+PW zQ`v?33_?Td;c#qCsA}s>4t6f5`#txk(fw4o8%3xn|!=ESxu`Z{Kb%OxV(K>H*M4VftnqgOE57`GAD+oG78c zv1mn)$hlv?r*HH5aH)3u>p`?t%a(29;CSB>5D;(&MS4i!C+97le@NkG)It*uBJ>Ec zglJo;!6tZjy2cRO0v~j*!13R|rc(Hs_Ag(*9>m&*x?_(jUBrKT-~m|RgPeH~a+A~T zG$*+Q^L+l=wV5mkXKlxaQXyXDl2Isf>5w279r$Se9gvWq{9zf7x#8EJQOW=F9Rmj@ zz-ai7l*saipDB?Vzdc0~5{89cAmuEGN;XhPkT`t0$*_)@d4@xBr1x(PUz5VA|2%4lbv>2r6!3hQ%oewi|J+@XU|}X&~Ktn5w1u5LAjVNt6sakX@HckUb{y3fvhgJfSw*{RacNX3F-T72zZGUgP8hu zyz!Xn5fZyXR#p}gk6;1vkh>?O15chjQG!VX_8l0_9v~?WM#Z-f4_9FFf<$;HfG(Ic z{)ES>8p)0Lp&PSpEj;^C10SoN_Yl{UFS5~~PsC|<4M9B-00r{Y%_M9G+&Mdj}YR5{;{utwIl!Q*eTI{;O%{G=>20V%}b(JcCB_U$5 zbdN^!<2Da}Wpq!Ka+f;oapud1De<6vXH&K`c^zA^q~p_tNt%IP-cJG#occ^gwk9rfDIJk2spsF@{diMhU=6~2Jw%tkB~?cVWfc z$Eh1TT?P6NVoPdN3lg7^dnmtd%h)vx?(sv`v67_3Zxd^$#isKkte zWUVxVcw{(m73>~r{vu956oHH5XIJRwGyP3imwNV`3Ao26H7AIddRZ{*+qUts%Z^6Q zluwdN^gcDX=p;pSklU&LSxv2rj`p-%TXHIHTeAQN|}k(CqU< z^at{#(G!xad{6?}pPooBOcR{_@|;iJpx#jX14 z7S<-ueiFW){W*Klh50^=djvq|0jgLRVBIqWL@6B5_oSLlZWgwrn5quSyWjv zA2^rvIL=?i#U|o7U6B!3i01}I7G#uqB9aA1EpbBak_sSVSTJBKC2Ozp78z^c>wdX+ zuX=dM{XT&#BD%9_73x+(8-avi#4*hAE7YU&?hF*BA zLTh6baeZ8L&xJ!=cjo&JqOSQGCr(w;^5x6*Jxcb~+v>5j#;a~|Hm|ta;t-Qdqfv81 zZaIkLq>4Gy`c~%IaGT5)&1>i-oUY-5{GBv|90}(Q2FE{czJW3E2$6`?E7G9si8BY* z{H}UMsltze5CR4nWYF$okOVrzj`}(Wt~m}ZO)yh2!k)_5o=ODi&V6R46_|Xs_dS~$A<1O-L z(*ec@6K4{NDA4I;YcY*vFx*G0iPZC!Oh2O71Rim_OVjaLl(z`{#WuYB#mu@ZXd6%< zx}85`wS%dp?GYMhFsH(xFBhe5YI=Z+iwl20S!QrEi|2LL+F(v@w{ zN?tZijfk1h;{N~RXYrI&v%e*~T};F5gC^!Bi*~F-7(4BLj~wLO;Xkf6C1G zAceD4Pb@a4wwL=a`l_oQTs!Hk=)uj5m#co~OWkDT+&;!GVQmm^LRiTl5j6T$zjF8EQ8&9S!9te$soijGVLsGy`l{;` zN)Veb^3PlMP0bI}=JpAM$Si{=W&q7L&5)YS|H)kRKd0uknFpaJOHOIOpzQi4eo@v0 zObjfkYQ7U@W(@PQbqW#V1xO=#bW>~IUG)B4H7eHBD7szG z=L+p})2;NE-No;iQgfVP^CbjcMEB8Fp}C)FGVa_HwJ!qk{g2Y{VRC`uP9Hea8nFJr z>^OgW_0kiB#Lilw?u#gMRwrLdUW}8lr#1%g!VVl?MBEtB&oj#OqUF*oGB?+vwFsvG zDicYM5UT?sJ;8C>3Ndp;Ry$GL1T_jqT~@nq+lbUDAO+eFbpR$ojG1gu&xIKq2?{7>&u3Z+WwSS8J*3M5g1+HN! z%tOw_Mdasf;(@CQqDo{3BU&u)b3e)Z^d;U83W6HJBp&ZF`-LuW%B_oBCzvw3=GpS~ z{ddx|KD<44IOF0hjk|)Q%kN->>Gj_8*}`@;N!C*Cqlkn*6^!kD*YqAvuCEkViuQ-B zo2Eux%a2a_o8!xrOzm{X7Ytd*-!VQweW*Ro7s*ea&aH@)V%_z~*`;7IQrVmEwjYU@ zChCPIwc7-~Xm?fPf*`*0>lwPkyyh>gD$3>fhsB2&X7+xSJ!~&n&y>g4*WXVJxkLsG z;xCgX4Cf@9cU3G^tv`}gGVc>c6ysJQxFRrGXrY{8W`H)!jr*G&HeU$W(sH%@g-^j} zt_v}9g!63XWD67wglHV}q6>_>LybBSiGU@o2HJ=_k*F6OuPiVBO0))I+#!fM5Ethz zpcf7(B&0og9{!;!0PI1pf%e5N@7#rc3`?Gsi^2eY6Q_m z28$sNd_?**VpG#n4b9RV(DZf`w^woGT>l!pda;KTPmr13;+hrD6i?q-a&qB1t$UB# zIjHfrEH#Qxc?>5HVE8rD{X*y%%8fQza3_uUMonBF(wKQT=+ScEKE&e|_Wxo^xtA&O zn?6phDyLz%jnzF>uKSt!L~_1|lJJeetfJ0ulwyeE_|peeQvxHEy$;z8>#{S4y&iZr zvsy0mdx-s{U^{CrqzFa(x@G%?Z>uM;otr#y97MUTe!HAUiW_0^E8(4PrQ;`0Xd;wV^Y+lOeZGy1SGSGNSrq= z2D>tW7H#4ZBN4d^0DKAXf*_2N;L#)selV;PY*yaGA-vhJ`M86>Y>u92ax5dQ_DZQ*LJs>VAFmdJ%m& z)zN+;#Cv>q-|oKD12guM^dBHjfX;K>Mz)iePH$c!CRE%RA>t*g!v>X(=|oNb7n%>l z#WrbLc})8OyBgigw^B$~KHd29U1pIP>{%+IndY+%wqSD0tUuVNj3n5pJH2rVYjLb* ze*W^UM7o%DC!teZtVrpYeNIVdtl1I0rie$XTGo!79zhnU9S`z!6> zGJaTKU~O%UC`i%20w5T=KH(~!7O($Mw89yNbhaoIb&eMV@RZf?3JJ4{!-{gtGqQ1i-;Fdcm< z$b1i%9nR;-b-|t2cVLA}CHuB76t3tY{41@&zwNQxWZ3FXFvmN4rTg=42h_jg*$-GH8A2z~!CjG#rw=Xh9 zO|~aRKQii7{Sw1{Ypb5Zse`{?^sTWH7o(~YXWMr1V!_6j)#TN@dX?`!wQVw_jVn@& z<_Vr3T*{oU5Q$ywTe=xnsy#dsGusz$`o6nlR4T!t%qD?e>%>3~wJ%dn8tyFGyD2HX z-}ve+%$$-n%ZrP?WC0K@&^f2VPLhyVV?q1f(B(((4V&wt7xnb@{l^ZZu%S;tRVMaU z*rTYUb!up+VY?3&wKD)ZIQ2edF8l#x> z0aGNQh=z)l1X>F!{Hfu%3xwaj+@QZcKKD1|!!L6u&e~j<)k|>Htk`o#(?;dF(r>PT zG-FiekNbJ@42PI^G#8Wkl1=gpiXL)1RooVBPtTwC9pUD)KGO+UE6|fEc`i9X;Lg^R zWOFbL145}M1_tik_g~+xZ7)`NM<|XVI5CAgi+v_^{y`g`HQ(fHUtIa+8Uegwzoqbq zWQ#=DvcQdD_0rgS%TA^N*F&D%viv5Z6Ot?d{x= zF4Dr3qw1htWb6j5<~jsDnyE~Gz2A#tN?$vbsNyjP?BT0AjtWZb^R zaGl%fNJ! zBQZUS*AcE1!~zZbBs5f4WM#GVh;5+N;9Kv8G*fou!Dxf4LI5+`1wvSdRIk@_T;ztm zPhwxgYN65P>C3z4rj8#e<%r;ndo!dVTfN?~Z@@{E|AmS3_*VO(qG{oS3sve6a8Yga zW%vNU#WxaCAqP?(yk5OM)C-*Xov3!N(R}w2REzl12hXHac+n z1jdcNNly1lEUI{(xUc9`U18lLTg`E;(z2sHZ~N}d`6upawR=J1!6DJ`pz>VpMCLU%AP9Ck)XgRLTIn`UFrmXiA_Wv$7VXX9!(3H&M2&;2~ByOql zQ-OZt0%=?VYON)B3e5J@cu=c3ey(Y+t$+D=H(et`#>=1Vt!Q;*hm-_s^P#V@a`!w*H| zhJ;WHvD)}FjjD_^#^0va$q{xr$3boLbTBU~e%>!jguJ>^()jFLF3UOqEV~T0ggSLL zH8dXQ(c&EB{?f=}$;dn^G{76eV(UGgHDuQr=j6E~;Jn-~^!LeU!b=v)C(#u7lZQfN zIi`o3zA~DMM+>f4kfXPC)WsH-~wwm1DS7x1^XD%ulM(--xBbTDrapX7F z`vWZ1?M=V8B$LVWIfS7w{BNbk+a$bazK%#9O6?C5(j!k7ZPlS`2#Fm@xB#Ps^Z9n@ zl=lk@tNzWH?w||HL9FBZ;0NcM^i5ghe-{oKDd8MRBgVff=@=W%q^og>z+ipQ?CZBk zOSZLAqGB*1#Led6uMm~U&iV&lRgg{h_{Mg70IN3&|2mXoUa`gU+7q* zG>`Qk#%a;TT}~zRJ9fOgS+YHQbxsLF%uC|pZxA0q@Z~^2e(~wkWyG)f2;19;<$og- zu$qX)^GWCER}NJMi0ypi)5Y6NJG57GBWCDIU@Ob`?C79$k36 zgtvy43H%Ph58#tfVa&+WJ*9Dc*T&78_a8e}G4m}9+1Xjy|H5M%G`L`V57fmlZn%FB zOe8lJ5lL8Mfs_p(>>-w<)41oVf#Q2TQTVo0>+!lF{W=>*bxmEJ$HDkvaj~KkeI5HlK$wA-`?-}=)xf^`|Ob`^b}wyZxau8x>$nEGm3uWvuW6a z6I5$Ikw!y+UGa8@3Gr`_Tt3@fW}yA5blcj?kl#Yf1Cfo*^!<$@I-jCe3LZv!JXaV!oASLphuV1`?rs3QeFaQ23Id2BF= zyACZFmX@b%)t=-W=_`N6`&fw1#WReKI@o^A^B8|~>(XOQbMUR*Iu)5g%iPqg7eCw!rsY!ZA^e?(d?jK(jj64#l zOIPzqBz9r{s6)FO>h;vG^}OQ4%KS;pyO=Ltvw5KquQI+;|D-)&vR-jbqH^BPz2L1e zVL<^@9~}!DWV|olV~KvFF+mF~kJGl#>XM<102DwdSJWI9*-&43ZAb77E(B8+S@7Uv zt+IFDzPyomIMQxmT{1s2jp8_yZcxap0J)zdcuQG1pmBa4Y!DNW0jj-e{&?8jfrRjb zD1r-}QH9Y~lw(9?G~O~k?4=_|^=xuhb5~W~{SX%B(<%b#i-(LHjI`MY6_GS_E4<}Kv59=}QIa-Ga)>@Ju5!dvw9qEenjWr?g|ks87-cogXAufm4` z$M=T&RM?5gz&7woBDG}*9L6=_#YiG34j{Jp2?4Q>$3VIs2GAt{af~lH#frWibU+?h-(hN8EG(vu{l6^3t=WoWYQ%vsl!oZ zwhOrVRy>%o$BFZA2Vw7 zhqqPT|2WPPDu0cOG<9`);6!p!ZSr)a@~X16dgpo)Y%V&?!*-J9#nZx6b3PATNubyE zbr5l!5^THI7E0F_#3Xb}vR=SZW|FsPsoutM?G(!wq=&(>iwibx?ECiJGtORo1l|~7 zn9~7la`J=g%hWWvO98mss3|xGTZCWE`IUwBEnQH(gS!O%g+hL)T z`m&f9!Eh3n>a|#oHH_(Pd8Jc99@LH5)npOzBs*{R=0|6 z=#$9EBQo15m+f-IYviw8BSGwAFqf@dwf{A>vCss)?9Qm;4ZHZ}s!kM!xu#eJMFr+k z#yTtwTw5=9w*7J}D5{yxeNN=1*$-%!x!P8K`^hryRrPA%LTh+?)vYV+F7-Kn!+|*w z3raTjYnA7OJ31MN+4!v{_9DGxBe;&=?PX)@l|L$o195{$y-CagTd|akj0|3zR`ugG z%UQ|E$v?9&`Y$ONoMK>{xn)GGAUmT|@MK9Kp9NJ|(IJ-u!`QsA> zO%DEbzk~4!Bn7T_i~-NG13~^o3Zv1|>g5ujKCn^@B0I@q-)2kSSS=l$ZkUG09jJ;U zB-H>@AVEN^;5r<&`g02?{F=tbl{jF<>lv1#l@I%x0R?i=Jhf|!8B1$m=KS=~r?#hq z_wqtJy?2Q0Am`FP6uExN()td6|8ylC{mw^GaU3MJG&Y(gep`WR+h2?eW0}O-OY9eI zrt4>$44Dk5!efjU*xdLhSDO~gUGZ7@DYoxH@Kb(%{uLD!!^t(DWsl~2=xcEA$tWq6 zLWF-W{R<};L`Szbly~6J*T%3%OmWEh06y<;P6j&`OruJ0kW0$TwQ!~hf|?LIhvd^I zMCdo<_z8dv!3oQikrJxq)W^fi00yn_Vh`P`F|oSxYcMMpx>6E7@DWF97 zk}jmG z7zI_~o%+v-(S|xYqL(lKK-hqcwWPg=)f)5y@9Y*$68i~LARqYu!P*tu(_=t7+_o(r*D7}9){R)NbT7MTH8zcmR z?H%bM-Q}L|yoXH}CT>7$T_DDll|Nm{yTVyq&LJce2uULR>T|(vj`>>@aIMNA0qWfN zkB#5W4Q#p&YWo{D!Vo%Vb<{Xzc6zIkEFd2g1#ZKpQ~KYQb0!}X!e?ABirtD9f8Mf! zbxtuXrenS>;EHJ^9@}uhCB-779zg~L`H$%wyLG?53yfom(Lv!U@o7R)yYovNAIRuq07DadP@i(Hl=@Pot#Cwc=}{DFc0&6|pP_dl*Z{4FG=izoq-Jeu@6G zQ3W}o92sF{bW(ypL%l%=vUzxjwr~PZ9GJ$DUe2;c+-Oq@)Q?YqDob3tEgQ~dec_cL zwr_Bz!m_gygbFxLN?2Q`MXX}oLJ&^D4#Da7S5#2w93~;qM}Gq&5k#8@j~HR~o{VkI1+(7!fJdN2kDzFki=XYgReLx+X^7PQ7F8@mN8IPtv+ zCOb};?K^f{;~G4y5rKQ1im;m|2>9eF@0{zWveB0!DIHOe%ntC52NC8nOmm6uorG@p zH5k~~>;S6XM4kx~!QSvDLoj$(U?qcDp9gja{;#x*%=)tk1UE*8XvnZI&{@Hm&*wth z1G54dN9Q$5+@qP3{o3ekxKG|XAS)tw=k{pchSgY}Z@g0@8dQ3a9*E}`4r}-G?gCRG zXfUB~GSPXX0C!=aG$!j_;5@GN>4i-W-eV$sG)P#e5&GS9>dqaErPFt`&@Ca-npe zn3zyUeH8aOo(D`q9`GQI6E8Ew#6SefvisGZJbp~2j)u0OQDLQF(^{((e-e$fC3;){ zF(A^@oQ10yN-oeadM;IQtgWqa#T5@+@hEI)X!sl^#X@*P!CD&|p7pP=T!lDfvV=XD z1YVDXiAln(fRK>=*ypexJLZPxdJ=md;J2YRrg88I!Jd@3a)c=$ZYuG&CVn9^62&z? zR`dt68`?0Sh1fC5#oC>=#butb4F_#FGAimQ^EcS0PDlE6TV0(O`p-o5ymiEbNRa>0 zUN6Es`VZ^Py z{dJ)@0K}8I(B&eyI#Ufm$gfF7Ss5Mz`vBq#E_B=ngWwsigSJcapI{=tr~M;C|#`zHxEY}4%UBJ`r92={^ z2_3y=w+R^GGCg7@(q67WkAoKMGiZtgM;AU_1OYUL$?F2D)J2#eKw(q&HzQRCwm_Hw z)e$5yC?uo5l`!X)zG#QnZH0wHe=APT*IjE9dyi%Inq=#y@Gp*J>d4XGwR>g4i zctfHAEv249!Rs{&E3NE~+7O#y@y#dbs3d&a^e<+!`?gq`mWY+_kI?xN=l5~`m|FS+ z%UgZL`FqMI$!qMq_osx!<=#9rXKZve+Ml5y@Ha~K&k6zIT!#*+gWPNf$r1txo+CLP zeoU2u(_4TxW3_M+Ko4=Ss~_K`$f})2W4F-h1TUP;Xc;m75Q{hh$il4vsO1JaW)KAw z5WN6{QBX&SPG~f z7X>W0=9eub#>%6}aZ?kYoHp4Vf7dok#}eETSk%^;_PoEi)u*&yOgQX7%6CfCO6l%{ z70&tF_)_^#o$2>dP~r=^6TqG#@;EWY)bpDvw}q4Qn0+F!SHf{oPwxnXohb7+baaZa z#ViKoP>QR?htZ9)Sm~(9s+#7CV9+PL?RK7^T}?nW9SC78@~=waQAq;-6GDea&{2E( z`d-4}h0$iVk6?rlIT6522)YzZK}jGwIzM@$H^YAPX!)t^TBewHmPtiz1wnG;S-RZ& z-PGLUU4nfo0YxndX*AC}fA;tp0L1Qe-2vJ0$%m zt!lxrpj>hMA?J|6?JQl#ZB(o4?xu5XUn-i>`9wY}UKViilH?}eJHDZ6>r`=04pdGut11S3bBzR)YG{9h9SdqgVjz>%r+bE7ExAH z2W`ANXNSw08yeL$<>yuElhc~tStjdDxS%;NdR4r)>ATv%36>uP?m9kLy)SL-_MxK0 zE$fo) za$KTh9mZAV%bI_GSW+{_BZHEYakxqCfn!d(ZK}>Eq1nO*zdAinIv$m$OtGF7v0JR< zvOY3=xMiiK%<(3WW z#(H|byBiXsnN^SC|6K>LLae@!qT-sTPNYMkVYe|g8=R6cNd^i}d{9Woz|4#7uqzqR z^Riz&`Aa>Eefd3E>RtXP>6L7iTncT>Czl4zb+|BgrCzyBb@zF|b^^*dM!D_#gBjLJ67mMbL5;vw+6ox0@_2rqy?52 z&GV7k+FBY_M%Q2Q;9DUmj3JQnm_6utV7T$+Ma$kd!oHu1d-qR{bs5eHDN8G3_Mi?EqcoWqRj*-V)E4o>_q{<%eax)VC6hEUG?Vx^|mePI0Mrxq- z<`&BbEqM=RcJf(vDYvRIH#FZCrU>e|2ll!>6ChpO{qmQ350%H)>Fxm|X&g>yJY%b$ zWj(TI)XHSpGnyqaDEflJmZk9}HIgca!`Ge+ai;%R){roZ+|;g%J3I=(IFvZB$TO&e zgt_vkojYM@C54eAJKLPS0Fn>J83D6_XM^TgfuqlXU&K2E3MO7|S9XEEYE~-ZyGPVt zI3nxg(%nH6@KN;!Q+jg?-1liytll}1acAbPu ztVM{K1Yv?^2H|+p9>-Q^aC2 zQu^GoEhp4UC>K6`JZ$EeD&UZ{Qs(vtW<WmGg*wH9Y0P%iy<9 zkDW97vxg1fH!Zxzn+fYcVhSr_vOMMZo|QsO!;q17Au5$>FE$&{(Qa5JLXoasy-GCK z=%Kr-L|F1OK)>wwihPElSKt#dsaWPFZ%< zzn9LnJNqKJE7J6P;a$Zl?(G+bJR@r4>ivGoNkhYeeQET3{m!o!lQoCU#m&75%@FA1 z1agLoKqzrhR$sh$@eYF{f&&30Y}s}EE_}pNu9dN33kVPH4``za%M;XQ9b^^2mN8Q` z2lPFHl=nO^u>94}_pMfE>-~>DGEU6ywIf@5B`fKr*LAjS6<;#gPAX033YobW5plHb zN7~#n8E%QNzGca=(h7M?lY`4!n5fNr^6FVm&05ZyYiSgoPcAgly3qa;7%sH}<-&Xp z$B9mdiOhqQ#aKv&Ddo3iiP6ruhtuTzd4(p6!>THo1N^b<7u0t6Hhomx7?K?7^?u;g zk;_Lwg!$RsnK{(rKfx#Mad$@%M?iT$PB@V;l5SwUKX@aR$Aagn#BQ;rr)J6Jt&c=) zX_v|eirRW@8{gU!LepdiQ!<& zfYbfo=7W|(PQrDFdl5UKXr>RRRU)(;xtnlsh19RwELPcSjQ`ra22Z`YgLQp#!@!lC z;&N@kbbo91u{WOOv^F%1`9>JP2^Y_RHSC30Ly69?x$_aZ)~%s$OOF_2k@^cKVPsmj)YFf1!rK z$q%xA)E@oj*FZk1#Mi0fP&2Nx{`$GAtLrasg(l zK{8!`8zOiE0|Usy-$Xc?o1aERQYZH2)UQHAA3>o=Nb+z&32rL%GqZJQI$1GDf-&CR z+xrmn28`;x@ws_dHj^5Yqrp&HKVwfUvEyrkj_l?(k*!b%ty87?f3LPA0!3^9n? z@I|j^V-5jI+zErPPPlE}9IA;x(Bfnvqw!}19uPPbp&`VDM_@)^Ja_hj!!2S>=HQN<8uoIb?IF;C zCh5IAERAwzgPR-+TqG$!LXw9sVkn*O!N%wvd|GiG4;?x38pn62HKaS@(@TFY^au}E zgkCi3D#NY)1RHFE=DS0ORUTQ!FEGbhX0F{$Eeog&@TUG(FGiIM#sonf9}0YDEcs^} z*3#w!McQ^|X1A0SUJxY0!w<;}GTwzpyoaafM~DI=qN5L-KK&9R?DfznOIcgw%cSBWO5=Zu|Bx>Z6$C!Chip#Z;YKFu!)VvZinWZjqOhGl7^Au+l(N5(l!t z_pz}(1d9riE)Z4DK#{5IadvrjIBc#tHR}XAMvb0g4~+F2aFF2hmFK!NHauJk67=;H zBPIYAuzI-NZa-h^AA$%qM@Nc&Z1>n$TZdm7LFf7U<);Dc<~NM~^? zV+lh0l+k5 zl}XQMzHs8HBT!06F<(P?fnJ!3Ajg1zK#;+SRF8xF{Aqa$C`)j2DF$U@n5_p36u`t< zKv!^sO<^nk&U#uKcU<|CDE`asL_uHCI?>Lu%6#{E%l0QZoS~r!h0&ApghbZI=c2iJ z(uMA?SMYpKp?cM%626GkRH)<$ejGqywqwU)-)hiNsV`3TiU;s{pki`Ecnr{quqlDw zmJnS-N$>@D6T)Tkz=9ceHNSJ`2DS&-*n0w{uhX}M1}i)wVjqqQ=)TWbj9ditZ)~CV zaQTPD{#DAU)ogUsq!a8K6C*v=FQsR}lBNphnC=GDG;(4M=)73U{UT6A|2w{k-aLAh zaBQ3PpJ6?V$92-I{#S@s{i9>tq9?HP81+uM5O zU620B?~!+P<#5+*E3lTB%LrQN>9Y_D<}z*l6dc#y)lU1@B}wBSfIkIqDp08^!<)SL zrn0;?b|$9P{a=mdji~9_hY*rLgn70*EFXmt3~s_Np%RSH>p#4I|9(U}96e@UU05o%n5@`XJq zVpC{Px2TAkMS!Ugp97drrI42w+bOGRK>F)B=ih-wxMH&`{VwsYX;J02&mwnE=ofZ0 z75;QL^2rg9Ao(&Uj~6QLZ!I#@x%uVd9_3-O$R~SVZyI+4(yQt9fxfAR8d;0-v?>yS zlCT^-*O~nbUT(7Zk*IEM>`%muGy<3x^y@njiobFd~PJsJ%#aYtUZ2MI>~u%>v9`JGO+G*mB2;o&i-uk^xywS*NTg)p z{iJxY&)K|+b;*_OMtZbQwy?JCs{DN6TwJ;oCfwbVBKw_>J}$tB7yW?q-<%$Q*SUp{o)FtJ}6Ub7zQXD+L;!733z9B_J zEh`>v|BU-!<%?ArA0K`XU>qmAPclY(Bnne2i7Ey0&uwvBoZ@;v*2WNQB;0bRk_mzU zo>_q)>wu;q#dP7Cq`W<@i}5|8a|Y(F9{;< z1cbVE#1<6wzRhl0f{?I5`MC&(uw8ub#?H?Y)=3i+aC35o=HMM-*sQmtPzzq+tomI*U3vLU&Fm%<;u+c#;~Cbw~@<` z22kxv*F8kpHA8#sr3wN`A}-9QEL}a#KWu7cSKYlZJM}Tnn?+QZ??YO5zqsbOuZdJv z+AksJN)&wxxYCx=rgA?}lWtGm$s3mBf=}aYS8n9`P&x|!_{Jw&K2%g?IwsE_94$!n zWT!p4Jm|s!gfn+#)!41FzIJTfrj5mPF6VIlG}$N7v9GMXCWqy(VqvoU?vS+FT32TW z^9i%zI#)Palrgz7s)f5y;^6pb3`r^tv*al#|+1b@M160#!(yFP5|7&CboTtoF? zB)724E1s|Q*DR4fhFL;7F0&#Dzypuf>hvt5>09O;{w+K?1Gb|Pj;0a?e}Qc|4&>nR zm+>C@^$gRcpY<4xRAnZc8&IK(hWeX0$VX9b*rt6UlXNo!A@nA9Gf2ceK19T)KMmOe)XRIcyQX< zQA{k-{+C+C@36v00x}*-!M^etn#?|TIU@mi<|`}H50)!2+7Yr+g6r4qF4ES~xDi5= zlUWtzXj^=1% z{}J1mh07*lc)jV%@$pG{At9(q!w6>4vVI$pHFC{&aWZ8-x3100l-=P>-s*I9%Rh8G zG#aPn3F;ByzXt9Vp`FTGfXf^h#5=I}$%h`rYNkr`j)g@b zHo(x45SF0W9<|#|)A;imA3S+-`&~?3{>0Tu zg8z0(=@t`6O=GTE-bcApo_YHfH5yl#m`zLboHu%RD0{!Z+p{cTf9^(|;-{qt4xQXs zBxlb4%D<`I!ZM|MpfBW_>@{id{p6!^P6{~uCk~kOcM;F?&uRx8Z_KU86MQ_D9~}4U z*t)$G=&c|dSd(eZ@|yX>!fj; zAYspiK?c~n4p51sKP9&OinWnKy4hhOtd#ISgm@i(don}}I^^v9VK*D;5yT17j^Y9S$MaTV1r^?*Jszk06zKFv@2xteiAq+MEg1m1x4&eTjjQb4>>bD7ey)_I3%y_>h-PDZ zOxWpCBn-S3KKus~NVBBEk)08o?GI&EPexpJ2--&L<5erGG`{q|klpN5H(SvJw=e#< zqI*1T+=o)X{XbDgDswi4!qBH|_P?HK?lbxrl106$J)=23m8D%tt3IwFHDA?wxIrP8 z$$nh-eP!)j(f=xw&I3G`80{PT`YEoisOeK2W8+tExy|=0F4rrMQ{bI-H~plVJUJbM z;vZi|5|0w5bzDi**@6wPH_wi@ThUAvxOjsaI875PaE3>1kv1)f1~h;8QoMshvrRn= zbuMCm2PUT6WBuA(+3(O*h=k_If{j>PaD?8LQ@hOX#Ef0^BwcfzSxC{m(sd!T)1%by z6VebnKb(Kge?7r3%;QW`sN#i!o{t zx;>C~dchfaZ^6g=7I2=G#ngcX4|RQ~FX4-lj`324HPu)J2cT_iD&<^@w{}7XITw~E+ zvZY`S=La#!1b8dH6}Wm2-YN+FMrssAHt1A z>VQ0uASpwO|0nN|*>2+J>IFYP2IxCQF`N>FB_JSBf%`JG&ql^X^mbdbBx1gzx8~Gn z9e|vE=3L@aE^?$#4*!a)SU;EVk{U$ZIs9bTYFnxG&oWMU^PX!zkazSRTbtNI#~>}X zj2ua(a}5f>g%3E@wCZQ>3xXsN`SQuPvcVpasK+qcx;GostFYD5dV1Sq+8)cSZItTe z(5u3vD5u!I5FO#Jn0?0a#rE5xKFBE`(ns>B9)biBYW@{?57BRU})%u zyHLI&Q4Vw2_ejamIK_a7L0(s>ix<_w7Rj8h5EyCA*a^>)LU$HpIXg%^;2w5*$P#=6VEl-jr3#|yQ`dd-o zzRhcM9;2)AvP(06+UkMs>O$^)n(Mw7*xVrOXqzSckMVDg$S408$yuH4?zq$TX5!f$ zyx~3>-<@Z&@1hK4_j7VJm`Eug8q!uN&c6MdZAh&tWP8l zo=&abap~!`4Lj(rN}qpGZbMPeH2r?)!#mlfaWW6<>ch1APam4q#DxI&1YeLtDWeJgiLIkEm{{aw_i^;yA@+< zIok9Rz4ZEt1`%fNu@t6-b4>G*pN?eP^@_c&6RnCg<{)igr#YAxkh}QXwAJYhhpSCq zlRtm_ZDGkXZg5ZS?z`urXt$jbEcOX0suqgw8~Lf#WrlC~{Gt>Q54<7!%rh^0#dV*@ zD_1W*mb{_fbv8um^Tb{>y7z|iDP*?gn7-7y{x#!Qg-sTK^yQ0$z*`_;?Vek{#7jzpd>yc~Y?EICi)O%3`J{Aa)epvzl<^aNFNWgO$j zT7bTQ74``Vwj6RH*a-z1`*?ZhA5BVta>)0V(p?V|N262+xG{N)9ZTf1iDex0eJbBx)%OnpUOi7~SHDRmoD0Y5I1$?KD3ljWJ&f^43apn77)q zg|Nfbgu)8M_!=8W(9vhY(~VHw#ae;X;!nkTJofk8KW1UVw><6>JanMn%9n=sv&dDqa!%)bi}; zG9{vW{fBk8jRz`H7;_4$8n@}t>U5h4Lx%-4aC_9G)dJ zACvBvq*s}gdap4?7aQSnI^N&!6dcS#WFx$ik5e^h%k*tu9kWbo+nFXyXiKr*|05(m zXX%;+?oU?-P%CfZFn!7_#E{rn2BK;7_E|WNk$~`Y^vryWI|mdA4jM$cHt8uoQ{){O zXedKC3{d;snKbKcAEbm<7faTU^bd47ha~Rr-B~&;*oG+hJG!DQ83Wgyii?MrSPRoK=5B6x@t@JaBY zzdNImun|wCrVBX0RA@hSXN@_(9;{Ph((tYV7WsQ*)Ez6)a{Us()q}{_!p`_$7yp5$H3bVF0|IiGx zB+#=7jwkdYi%>QyU||BsYMz358L@UgzB9L_%7hGjGVkHhyR+0>y+_s3=O+)2=q2Ah z;-^NNUcmXogq&|3a_VVJ_kAa7&#Z&~BaSzfYQu~_hf|GZkL_6=*>xrGe0!Fzr7K@~ zOc@^^|FfhcE>mAj;22=IWJgLDZhRSIn*7|`LzFycCmg)WpJP46%j2F>`)AOoFq}|l zg;TyRtS;JzS5ICAL7M<6Fe(w!SZJBG06^4da+yRy;6bEn6B%CMbm}%Hu+gzg-h_d{ zufcHL{&DBdBCzD{dwcIBn65-yHw^_GE_m@@NuoF$_acSnE@T{66cjF@>I1w2(fg!9 z!@FQZ_fGB)5s}fXY-b*R`Ea%Dp7w8#zONnNwaQZ$-aWlZVCP6r?DDuqS?CEKcjKSh zexMem#=E@L8kcmZJ+I_mXXzu)Gbdh3RP)?0x^>V%V;BCwdxr78?!w&sdj?iU>p4VY z->94yczrd5baBY%ytIW!6>r^+&AC09B~~dDec(JCK6<40zBBE+>zrnLnmm@Z+vQnU z0y{x%B_W!a(NSnEMP^D&^N6r*)4F$-?PR6&E8}fR^?Ri*`V`efaMh)b4=LvKa-Hv~ z@bvTh1lEDGySomI)91FXxgb6;EzltqFP`zV__C@1y(=$qwm^xf!^MPkpsq| zkc!W3{W#Xu-Ax2dV`JEXpxDz*=OBu3c1~r}=NgK4j((}IN73H-VIY0o@(Q~};NH3& z`YGQ8WkdHpv)2FUp)`y?N$l@nl$csK2cw7MH;bPI^B-AT=A^x@U>};Eo`%S=4}5Oz znsDhI^z?*5BH&EddV<&iewERMOcSTZcui_TI0d!=y1Z%Vju{M5b1=+r1^=Ds8M_{{ zr{3=Tt=x1TKGj%Ecdt^j*qy}~NJVfq30gmp?oe!eVTe@?^WP0ycAbUt;{+KN5xtNN z6hSrtUwo`e4ODZ8432q63NHv>AEB7XD?LLzP?RvV1DG$l;jE8Dl@tEuoQm%^-i1hn zfDF)h9rrJX+_^??74mKbRS|95ZV?AT7}!V7lw&dM`sJ+1F?&<^k~Sq9ma0*fo_F}?Do-n0a5br9<&?gRwzi>( zTgthdsUujD_55&yQdUkif7s*G1qtCgvpOhuY;`+Isc9Xq7=I&+uPDO|C>T5%#CmZ> z$;T1nt)1>SPQ`mq3uOXn}mXbZxtET_IS{~uz^RI z#eSG>VB1sMyo3Z3;+jI-*=E&EL$slCa`Z5-=UyTrRFP!if@=pL56??nH3LLly^yZL z;qFH$YjK1shg2f9#~G3mWLm%yxN_m-K4IY?m_AQ{E)|d6Qkgb4GK^AB7@>8&&Pfm3 zg$3*~o)l>O9v)t->;CjDdmd^rEoH1!eGvZpQrLcpG|?|Y@dX_gRH|XERq!kj zeSR6T4nUv?p|}U-3iz8(g@K;1A2{$`xTGDILc$wKeVEojs=4K?xcC+fSNLGM`}(wJ zZhd*P2}~=}!s6ncdKF7)z_Wu=2~269a&6rEx^>ZwQcVJ95%A`?R2{qv zf+bXYB3X%=*@|=*3R|yZDvHCYU`P|Bb`tY)k!Im)^7`hwruLA>)U^4smCdNq*_Mmz zZew5~u2f?CwebS>cYPFIUX9XkrjK)S|3@DwXOA0f7hLTRdPbg%BgLH_xWQmHX$ze9gfwC;wUkJ{ZZ6#6w8(71TC@dCWJv$=%*MipPNcW zr6U~ZVI5x^rc)Vox)3hj_#VGlS*1#67dAIDx)l5ZeOI7HY7m?XZi8754NMtu!KceG zlgZVHuUYatsdYK9ZsWl2E5obLw(aZD>Y21iNokx|+2CgHFcN04rl#%L870X+#HE&9 zhBH6`0uO?=22V!9^Z~>Ls@l_u)nC3uOP;MK>}`_T^G3~Y411p!8Iy;FP&J=Rfrc{V zhRTWM^r+ycV;u#ZQc~tm7xnk|)BSkG_H~9ZLOe`Ctmxi+7cpL>uRS9Z_a8lD)=}jw z75yxh&)jz}iL&3ZYQ14{)zpe|Z{B)goVHra%sc%XaieEvG$atnu)wqepN92UR36<# zfBUN~L}L)@oHB09bO?DNa1}wv*f@Q_Rk#>wi;2CzzX&uMLeocr-Uxlb^_MqI?%c^k z{>0FZm7g%efM?LXTFYkWa18VM@z}(Kgxe-2uhC=i?%BC(mosE!gbrm7|CCq09BxE7 zgA#)hZcl=^K*W|qh37BUzH)7hrgiXS`ev11E%VAp3VDaKr1hs|8OMx}%o4_ z3-JpofnI3ZGO^$mX>N-pN(~H_yAgdtL>r5;*zd5koM&`1H8aD`{SjcxM4MSX!cYcu z8&MFVvI^!f0^WxE$sb`<<$f0+kHHT>HIy<_o-|@(yOUaePfuAD_l}XHdoA^kxt?QC znmv(nvb&?_Y+WQL-00vR6+L|hbSNG8*2_7zBJ%9duPM{W>PhMU?D#hJP9uh zrS0J@*6`}Rgd-h4A~bW*?0&?+;yMQ`9L^p%)9?romZ92}K`NR--*2WTBq;=i6YMm? zk$|)dMGn&OxA=%#?B`nrmj*)Y0I7>KlSx4~Lx+jrVc->m2-ha!+6pbqg#Tkb9FFKBf60<98=R` z5)xXUU;PY^T0&21`%RZ>dDpa{R#wC$yW)+?74}zd1U<@#xXBR<$&I7~+i$8}%j57F z>Tv_Z8Yw;}v=bZK))ceFOwp3iUFGxC+q}{P)J6!L)s2Wpz_aMnXZl+o7rw+x^A zX#bR8N4XQNO4|+P>etLJ#frWKzt=ilZ@Be)*2l%h*1_eqNs{UxR!Jks8d<^^i@XnO z=$dw)*4u&RpHM+gIEk#>1AIl4V>lcP30+S!jaJF;_CKb_S#=ms-9rP5vaKCeKt#8;Guk3g7Hoj98^b5brsLkOLwF7w7^E`rbhF zONfz(U*M=}^7z9YSn7|4406%^K=~k%Bq*5#_a6Cs4atU#BpAvPx;%p12vwK{kH0nO zmsGm-u}t(X5Ak2tsmEW(+yiJ)F~$QKEY92ZUzCy}E*`*}kkPl^sv0=3@L@gk^7<7g zKf2hHO~HtHB@FZMK!RS^iI^>(CR7?QP9tYuK7Xz;Gp#rFFwu#-f+k?{hlzwIG4I1) zw0YW0&jf|-PPE?gka}~YpglK9BI8s+%cru=Bqvw0Q$15*;$wCyq4lJT?o#Zw5 zGl!%`?S7C?~NyKV`kpd7@)HlXHU5h;^u0UDxCYMpZAIha=49__uGff zYRxxi#PlU;tqzZ_UCtiK&THNkm{kaJ0}?52ob-j61yu(wE9M}?BN8PCMqC&~7QBcA zqyM9s3XhKNc`2`Y1A_+EOgqCJe4-i+LSMbQi>bNseIa3>kDHrBh#3{K?b51}Av;#J zpOwWFy*?L5l@1;O!X*p_?ZkeOh%JG5;0(;Kkz1x05LsDKK{&r8#lk^e9vZbRxtbKK zveb49b)_f=p`fuFv)S@yTwl7sxX%9@zS|fsTu$!gP}`m){6x-PNp}47t>c^ezQe6p z6xB$3>5ltBX2BolNhF#Th7LHt(bUHsit5Ov2;_#J4$*B&IxLaF)BAbooL%s$ePCTq z8+ol`L9`8UF0>TDp@@+djy5Lv0j)tAgxDQRaNrhMQ7RNpHPvHOHNW2PGiXO*H|{9SaLqT{vq?xwDakL zsXK`6c&h{Wz{At;++u;rkz=yYAkgaQ%p>jSr#DUOIqC9oC*7a(kMejLhJ`1lE-`g! zChKyJ4e#v#Nya+udEq`0yM6V13r@r7(QAZbld!1j$4f||Nd&e|s8nHXuV5@P^C+| zadU3g?*i>cEA*l|q5(ny$YXq4yT@~yy_>1SzSSJy~zl$=@ zaA|QE@|6#jmF~zO{G4TLNy01OctMT{HTE(Afr0!sGvSk_jDVu@NkOm1@g!L z3z?H!RZP;u2SZ1Yd~wiDO_})DTTPX)6A=tpe-PADEcd5z;;yUJvi|kyuDs#69LWn8 zzQabL#z_B&RiH@3ztcIG9En6E~a z2a5#b0fC}VxCa^v0-5e1kZ=mHNL!@O z1ria<0NER{3Wp{W2rZnF6Nk{(or4+7*H}=b6#|d;?{fzY2j?a-4FRY_TCau8+^@@c z^A&g*-KO`4!9>;qPkf|Jh1=JGdr!cgUD*bF5p*(*rwr-(ytF?Yd=zh*CmH1s^FgVz zW8kcoHCxPbQnKFW;BAt!T0b4GI{bp(OJnOPx>KARl^PPrcjc)kN(Q7Zj`==y3>V4S zjrMq)PnBy}?G7SYN$5mfbKKT4r_x$|o>T@UlSW!oC|<{EGAu_=7t?L;J7KO@{w6yr zs`;p^==q`g&Fun~9J*oS7FCZ+ChZX-8_o%_u|0If|y2mc?QpT&H zgeu%uP_bMfC);H!P-wJtN)I*2zpi!;mUAZ;AzTlzfi^S^e+vUC=6W1dc8Ha? zcj{s38_COW5iuUur#j>N#c6BK_?0+)$R-fcC?99KHjJ!%fp&zI_ig!lL+1*&WXo?F z^c))tF8l8P4`^=?`*37ZJGw6a1LHe)lXnieer|vb8oo)>J=9LuLK6QFRKE*w)r-H* zSwBJt1quYAuFKfQLi-32zk`^@^4!d=*Y$DzYSz|#0(=wa>toA?+gXYzFG3;{t~)oT zdgP2ZI~8bjK89(7VaM4JrVd!D=wN1yR!n*V%3J$$zO`y%WC^FChDJD_>^ga~xH5Z; zvO2Ke59iGZqdgDNp}`@^&&ujY97v?hctb|V=0vAn4-YH=+WeBmWB*t|NSdesyOq$6A;O8$`lf+BC|yH-$V-3B^=`33URg zY78RABs>$uScYFS86qiccDBHPhft7**aJC4>^Ch8X#9AM zD^IuV-4uRq0fXwThERjd#~%3$1TT?tN%Gw$FOrD9RdVEy1J5 z51(XhxCWQT%k`gM1!$cH1WzH$<}}cweE2NEE;Al9YclXkZx~OZFr5zZ2spqv3xxjQVASp+?ux&}D3pQTjsgq9kCkClSUAKO7?Q29RNBbab@j zG_Z|-f_l`ifU2U@T8y=9x?7-;rxE|m&rk2E>l!ZSzhn@*6V|^BIN6f2fxLt-RGte^ zi9M3m-Pdz|ZoXYcPCD;lsdve-Bd;x8=zp~xr$1WEZ|`U7eN3SMq6=CQo8VkZ{hc87z$lc2kc`(;A{i&nf1FfVeG{eF-4vQCbk-}6bx|TkJrsN{Dbk7 zds3s$*)$uH;1iiV;Y}AV93CEfnd0y7n=UZ7`|&=l&wh^{&F*(xoFh{jzI98^LDf=& zRWX5uf(=>{BybOj?K~jV&QIk_i~yBsZf}=F)iaj+24oB{4Ua${3>w2HMBZhf{N*L& z>hKJ7baidxOpVR0tD~m&S6RK7W?_Cy=}i?*49iJqg*9bc#$;oZbqP%Om_+TkomCUt z3qIX(Qa*RXKWbkXn}}Qd3wD=*0rh$LbD5DJ9#ygLAXPiHuOzvw-KtV*i$proRv3qy zQQ^h=_eaXZZ~t1RzA3(iUFsIszqcHJkO+?(^eiTU@jVg=?@wH{YR;l*6W+IP4WKP7 zA+Lkb_G@bz6ezND=PmS@+Hoq}0dLFi(5_f9-#$$P%-pqyYfEr&&seX%mo4sE0NK`e z2T#5-!wG4eZr0kp3LU<=YvTdc=Dr^u_$6!wu1cPC5kEdZN}Z2Q7p>(pHoP#gqIsw# zhjjAJj-NmMy4OK?fY3#(1uq%W4(7;%EMHqC7=mU2o|A~oWh_1*#C;li+)v~SnE$Y6 z-U2M|5^e$l+<_Sxm??nW=m?Wngz*x_C&Ypqbo8Jum(BnKFJ2y)mJy^(#4gf2)$F7t z;vL`$PLvEdwIcJm_i!WH768fbF-FM+3u-_5o}%C+u-AF%yNMxf@sbifM;GyUajMsX zZ8J%6L2;0^S-v6F_k%9&Yat3AIx+L}5Y*1skvCwx2V#~t12>wFQQ3}C0KnfP3AcK?Od*}=7{KcT3;vA5zJjTC7 zQiQWVk^D*6I0K`uJmYj>^BP3~lh#kuqaRGF@4w1%Ka}k3_+l=lY5wtsuJY09B0m*Z ziEI5uqY~12WW)pHy>{W^iWPR|Upy<$m7aH+_^|xaVCG!XwP%ePMzKdj?{nXKt*G_Z zqN%d7|8X8W#R<e-awXb1BdHY!PDswP!-uwU`!BGn2U1{)3NWnOzhhD<9etWJ z=vfDTeWr&;wRb~&J8s8`f4TaY_QBO>@wQ!;@{rILFMjBp`pwo5U&2>WLwFFOl0fm9 z2D#Levv7R)C^@eNo>!*^u?)s9~3h!c7I;-wkg*%@FkE z#PRdT`t{jBi*ry;x-lWlom^B~Bl9*WrTeP@e0q?piPowJU>Bj?1MU(I)&X@O?H(6p z_Pu!9qBt7%+y@%2Jr{>A6Ck<{c7#|x4#QOz9l9vBFCJ0s9@uZqcq#t8wvv+ViRZy& zP(H7u^Z*zQSVE-Dp3Bj5U`GSXASYGLQxTIadvNdDH-o;Ca_}_1P!ELKb zW<%f=w8M&AN3mP}`BA^e^bN9@e|>yo_&3~m`d`7jBJUla;~e?_c`NygoWk`3@*R`V z-{?5Vv44M`flooL&r6os=*cFp$-zeI!3F7Ae-`#P6DP76)0-BY9o-k%0XvdB){pDh zB1d@-VPgzz68pz9_db>)u5<3&S$=T8yqS@+I0*Tw zy~JK=vcC>ngO|g2BmaQ0-)0i{Lacxyn(@nEu{afIg{Gdz==)ovOqbwKNlB0z1Ct6s zq0Y?A#D)*1gv*H4ztri|+%qmP8OOo&#SQ}nnQ)yOpe(rHr&z_n5b^ZsQ@P&3>Nvu# z6hnd>7DGe~x_2VZZn#sqqunA@>~Iw%JThG&>$99}u&scTH>$-cFglUoY=9Lq_HIq@ zSO}*TBGMEKU)0e8WO^beHO`()v~R4UOh6ZKcz%SU_iA4(76M>@dlBnKEcAjT{1;(a zYEF6aD=UAyn(@m%gQBJt%&$(o+Ru{yNXXPm<(uw01E1j63FRWrjoLnS%#DK!;$3UX z>X_T8b4^{Ix466}sS?%l=kj+(O^lbvbY)PRbU`88?9P=KC}DJYb6mKJj%*ws`0DQ$ z{uer2b2apTZR1TwSr;dt_J}CO=b2Euyj4&6YL{Tz5J;RNpJ6Nhw*oJX<9cnyzc<}` zw~*O!D0M|AH9~j{nhj%Xn~zgP*iSA%n+dBL1jnv4OINO4dl|~ix0)HXJ)T~K2Q6Iu z@54UuZ+~u>i4_|nRrh~_#6hzCxX^@O5Ds`krA(On!{*1Nv5BDXz=;wikQS_-^tp*T zzKN+0e=VIj6}b7UMTcEiw&DT`WntRvrR?f&LAl}|{zNT6D1G9c#o$nCjvfE-&Zh>h zvSDUDRz98=hj~mm>P`sM*>b z;oK`g{sOzwJF&UolFos+v9LNyo}k)x zvBQ@L&K{_Y^0&zN-^lK=rzq24MZl5je=<>Paky8WCb3F=~-V_(EO? zFEz(ua>I>QqqptDIR&MU9~l@%ssr;4zox8`6&Bb|t?1ht(No88MLxneg!DrqNrF5$ zXNz*N^_1UCU=M(3}G8JZ2h>@f`Rn; z?=}5alPc=$;ywHl4z0fxC)2C5Ft9z})>s+wk!*~)@Ye0yHLo%N+g35#vf~as90NaB zL91|mdp{$1Vn6l0wGf9@q~iJWdQJ*UKEGDvEDIGgdTY@UyA25%(J_RhH}=`qbu>g~ z2>M4PLmuu-caW&6)6&#rMdJ2J!q8hn?wkMP$4isQ>?3^~C+?^Q?8T*Xq*8GZ_OyM)#OGwwGkYHUYHJF;Jc`lQ` z>dgD5p1=8>3sYxcI{s#>Gc)tss5KY&Kkm&_U^5--DD>7z{yP8pI0KOj{&@ez8?flY zb8P_bx{|Zm2MNvyHkVHr>W$uZ^r|^KP#wzok{`RiBh_z99qrFEv$$sSsU{}?G~7nJ z<_pZhE*?!EQ}j7@N0om)SDev1tsrpbLTPzJ`%s%)qU>6M#)bby{M7ZfSI;mZ^Sdrq z&Tkaq%18>P-DrwU+VR)Evj&~0yXG9rKpv*2| z`u>7v^7I${o$Yr<>bGtaB)5uo$*V{#`(FRm3*1iwpLz2enTg0%(ciSS>V*4UbMtFi z%!bZ;GZLq1>Pt+O7|afoMN$3NRas@s`3LWBF&?;>9pT>AGN_=-H4X-g6mfEo->TVSUKj(7XhYZg7Y{=IyKxuw+(J;{|@VhzAs$n6fUU{<$ymsd@E zrpuGU*CmQL-vV$3s%N~Fe_F*aaU|ZfR4{#jyW>^IBV2{3NlNN#G0pOXiKeFtOY5B* zgeGcuNOG4$b-+#<&lJ!4oAH_XpGetnty$$9@bWl|wv&W4FAjV3v7CsQjOJ-XhTHd< zG3BHMRWCM)&}g-!ug_1c8OWrXvO13`h-1`q2x>x(%!dz$b#!zH&WE_TIJm&IhW`sS z9)F(*fE^8{E~1VJzYk#22-K4VRp8Pnb1Y?E7<_|g7(0oq7F7H9j!D+xe~)1D zwCwq|r)?}VTJ?5P_Qx;Ri$5dvt&G{jTI4xC3<0183Z+l!l!h&z?vVb!$OC`RSj%kxnX&5i zpgWp@Sol*h7e(D@t>g6NGxG8TI}zggx?eU+zFN`3{%~8}bamguofIdqX8>B&{0sf% z=;Nh-x` zkh|LV!%fQgd{9QtyBfw-TJMqvb$;uXEsHU$S+aOK?B9U~%Uy|0M?2!S0G~TRe-rlF z?^b#`o-AEisaxcy^?Tl~a?#y6lMrdwHxU!`eiA;!$_< zZJF~MszSL|I9&%Jk_})q;2mw13Ew0i_B`XQ~&GoSC$Avo&V4#KX#`(Cnm}EVsr>=nA}95G3(q9h0xmRjWPPl z;x4ngFP#4uQS`CVK*v>@j3t6`R7r2@a>vz%>%K3EoZsACK|N zH>vkJsp%w{+m&kL`{!jmOOqYW8DE%Nd;nbbn5K@&g02R-INDFZ20swuNrH{?2aFkm zl!eU38;?X3gZND_Ct#@c0&Pb4+K(g1K?2%DB0Q&+=3w`A$I~-Dm2t}!Df|No4L=c! z2j6%b8-B2IqpchMlhqmBTOuMT)ZBc2PNORPN|3pYZD*tZKy(G`P4=5tnAM%LDe^LG z^Q`l>tkNzkIR!Xv4%Xk1H)4YtiGPN6Y&CbxsX691ZuneS=VLpB0 z;&OEJ1-eG8FQmG59qz8b)h8b>WYtc0);Vy#SUGd&Rp*V-Gl@$snSZ^szGPJ}m*73+ zLtJI7B4=`J)_QLk6TdFbKNxjFWeqV0e!7B3r~h69mUl;vsEo5Zh&JS0m5KeK`7-}i z)stSW*f~$Vcj2Cq3Sa4IuIj!q#pF zkO59w+XP^QQFHW0wlH7Lg70U~3=mjSUlSz^>r#xe9))^4Ko0=nF-oX5ac;X%9ro0~ zHsNSxkbP^F%KpcyT7U^sOy5dOl+Kt{r`d7k_^-|XQWGbq>s&W8Z{CpSk1|)*5w`T{ z(4}WY`wTszg6jFZvb73jf%BIuca$->j#q;;nS~4CA+UPSZ zB3=KBnp)E7ynJl+(@XL+XPtS;wj-ulGm>+*REnXlY=kP>bc!I#e%F34l*0~gub3HUTQ#F)*0Gyt?WwRq%r;f6imIS z6va}0R=b#OYRH#CDlABjve0c{_4|=0;1^k5Q1B-NZ_plWnJ%7o-8d*wo4rv93xj;(Tgz3>uUTQf{XI`@-;@Z z*G};R+k)1Q<10=z^yk9}>58+K5wiw!&4jxxb|%XLx9mdtyP? zTbQ3vTg`@@Sa840!1banhvmxGlsl!vbvkIrNkIBq+pkqrW-XpnrnRzunb?#8Gt0I! zi&Hs$`t(y2ZkWzLZ@jS~~|x z{_1@-RyrY&q@)8F%PGfA#QL9s7`pzi1QtMY3#ZGusGaUcrm)f@va4KaU24 z2A7JRDY~_Bb^Pi*I1XypT*<4Bk+-?r8ypSFwl762tlWTHW)?cTmLz8?cgt(#b~KQ% zWDpFo3cR_Geyc7EGfOgOCo8{9V;0Ddf^+>>=wn4n?iOr18Kz-2*xG#eX0VWh+l`Fn z?WU!#EKchNO@80;b~#a!>u5}_j2_uGkshBPDgRri{&ePy8;F5gRxvgViR@!>XO$MT z`QSgrpKBHcw#Ol~9#NFcMVxP1sB(Jh2S_Q^h=oKz4)=gFY-sS{eZf!yR}hBt5}&NV z#u#UOU2p*qErQ0j5Lzveoj(}YJb*0qJpv4(T;#>ZHzJCBD=6AnW8b69c5sbv&Y@H+ zl-AV8@8myocpxD)Vv{a~3A)q2TjN9(#r>p*qr0|6bf!sEhIm!+3i{dK&2qUeI^|F6 zjZ>c0OKMwA-V^WihB*`5gm2~Io3=S}0fckt9&K*@GclJ@;I3_ksPn%!a!RRqlTosLu+BwontAE4`wguD;S?r-!4? zK-~1`s+DV+aj`#4nXG}1X&3FoVQzI=PFgpvZE`)I&hyLG-AZ{C@a~RwpZdGez|j-4 z95-%nUn6x-KB6g%+Q99C-d%Z4l!P4(c4$4nvU^@;{vULb9#6i3wA9pwuXgPdRX-`e zyC{b}sRwrn@;(8%u}&?~6I85Hf1LtN+HEV&SIq z-P_jr)*Xd`8eme4R*k>Yd}Rpfm+t?Pep%8+S$RA7YJqMrmEE{qy~M4K!&W9LLb?PX!U7OB-_45F z(mQkOu?_1=F|b^)?<})AarYM3##NvT?%?CAtkJH2JT2R`Awx8fecwIq*v52YlejwF z>DjpQ00qkx8)P>~dC8V2FCyvdQUt)JY2DdGy{CePO@e<*pb%8R7>tbO2;0HN z31uve3C0xIT}1K*5u88-cuh8u*>bq=BKDM|^j764knKI1>4K2#wi7VHo;|BvfzN>- zA_O1SIXkc(0iP3#5Yju<==6zNqeom?#AE?MT^ZIJ@ullvlm{dcD125^6C3^oCXQOW zhm{##%jNH3d0iWG^_kbAe0m32E@oOtaQAKxti9`!(D}+h6mD*9eHrKJqXTM>y}an$ z=vj)OcOvpv&;6kBRNuhHRt`^2f{F#nKjG>IA;~Zhe}#B`*+701!qc3I;EHeKHwIJx zkIkD`WI@F_1=|W@Zwt}@kzoxv$|!jBmxByIK_%kMU?e~&IALu=h*!fPbMUdiTBcn5 z)ScBF=KDI`YI0@nWUZeT&#yyx%Fhp5iW5gqtSu&WP!J-uDB@rMz*%g`{eXZwl~*~$ z#4PSfpV?;oWtaRH<+bLQGUeUu`)^-!LUXo zY?cWRSwM@goTf)6EQ%f#~Q1dQAdgfkC5zn!^V|w8pb#cBNo6e{*3=>T1V)2$1*@E*-jQ@K%%j zGieA9P)H_Qu`P!*;~hvfNZ4S|bN&K@YDqNLV4?pl_UER%3Hao4Pz0JFfzmnX;JfK~+j35ycb110ULlYC>pySo#VgJg(&COk959Lx`pqSM0LrM7h?6YiH6YPHeX+Sn!eXcnm4^vsJ%MtV$XtDtNP(kaSjfC0G zpMR2EfBg6nG~@2>e(1{AorI-hQzm4N@h+0*UP*7d%g9v*LZORx{O2S1<&jqeI}rm(f|(W~+3~8SSXg8OX|s}P^=$XAG2Vs80BRC* z+5!|PN6bkO7Qnb ziby+kq7I`^93-cNKDWuXqi7QmwgpE6+}EJnf5F#2w)Xsh77+Z)*k_f5i1_0kdJoSA z0NNMR?RW^rBpA}?-<-em?6^BGWQfMj85tRbT?c3h1evI&7GL`w9u7PXaEEwv{`E1? z#RjYGLu#De$hK2S&W_qYj*;9#nB253NVw;LSF!AU(JV+7j1FEupSvCB#$;Ccb8RJ2 zCl=ISZb&c=uv$CPU10zz&X1r8M?1UCS41rrR?^dlV+@xG6|JdxwlS4ppktvAiB2A{ zk&xda=i0aPY>&Enx}@dix5$tS;+o5&J3_7DbwJoT{7_|_pc_OPSm_^PvS;?}fs;a7HQPSdZnx@;wA;qA-F{7^Lw{3rW zVYltKpi;SixvyRc4&_LyF)sTT0RVp)$+%}P^bp_{gV--<+3pel(+vo3W1%mKN%>+i zX}{`HF)hh;ud|?ty(CH?_H({OJe3YrWQ}vZ;|Yb>Mc~+j{a+!@7CWkDnbX1jM%tx4EgspoB%K{rDtAiXc4Q}sltxTt9Aq)O3TCLrKccR?)IZ8BoY9Cr@f9Te(a)FP5 z+8ld%@3L#LY(K>Dkk`6ssM`IWLZ*WK!94Z$4BDpndsh81Gh3hWt<>5u@VWlWzUR~0 zc?@_=T3QE=MYAUS;Eh@{klP?MSs^5Tbz&Vmm)EC?@(r$IpRP6T9$j%Wk$%U!i+}P* zdCP9#kDF}E&};sK|D8e%C>p!{6?KT2R<9gK0SaJJaF|kES-N(i=(L4&PL8y6jSA^95t3 zr0WLoYRXZ2H^wt91m;PhQp^gmT1 zIM9(0^DS13%@q`HaM4OYgbCo*KK5++?#Wo<-b}c90ToxbsR~MXDiw$DP-l?YS4g-? zL~+8-Xw3nIg{-9vXDKeu;H!N^r}O$^{4R)YTd+Bv(1lw01lBAx1P+CIwX7L}!J5qT z$(m=+-WOA7nxr`QQ={C^mk&?rT=x8O2g24;RfTxT;{&}kfynwzPSW?({3wyqA1lz2a~GQqKO#rpyMg%)qNm0B!v9pC+E zRt9azyVlgLF678jr_rAzOsVfodU;WBXqslmx#6DW(T?4W=Y7yk4pF}}jq*|0dlzrL zbKh30zYqsv17i=&6(lzDEDs?`gk{w356v-2NH$GqGUz9K6F6JUuAv%W9oDb4k>*>J z@;z+ytWcuVyDT3?7$`}>J?WnDU@ZBF$t!8UzQHq(c58=Gp{L5`_F~pTH&~#|Ts3f( zqRyI&^b@eWwsf zqgjF7PeN0E|FlJa@rzm3F2kB#Ioy4NrTSJrCO(fdEpEBXmua~y=U<~&eMg&F&D!e; zACFUQw_@m2)rP}fhCha?Q!dt<@G#go-w$2mcy9kwCR%@Hy?&1ba!J#UKVlzf&ZbT% ztJkZexjgww$?v^4kEo3xu)LHqtEkapqxm2vfk8{XMH|s|2K&xFcR>+_k;u7c$Ci_b zd_N#9ICP0N7hN$}<~SoXpRL$8>5pIPy-x0Gx}4-auQi`bu9EiKn+uASA%yRQV&qeK zIfDd6LOP4!E_QZ4?mswXgdHCYO5dAlX?^Xq5mKG$w6XUad#){ceCx@>pDL;zYAMY< zIG`}tI z2V{OWQ0<543f{YTK?OF5*NKosAJV1@LtuVLb!!XhtA|CF4-aT<}71f?0#?DxS{gy5)D#)3zarUV2&X8m@vWwxh)?e zHC4knM*Z#}wVJsWQ+j6$k29PHEo_=D%9)7!MQ^0jb-qyJo4@?pS(JA4&ApQ{^R zWekr@wzlUzB&iG9T^AdjtiPrnqG>HSGp^t>KN*=JF6LU3Tf)xH)>7BfWU1G&?%=$G zFV4N;6N6lM%oJnybnQh z3EvMQf0uAK>8*;Ty@c+Da6v-p9>D^C82TTCK)e^RaY-sJt@AEb6tEih_e}OTkFdE{ zE6O|KYn*R4W51sF&@D5q>Bk+;j}_TJtY|UH9%ZiUyBc2As`++Hs@u43RhwF&|K{Ur z?~DdwjPoy;DsGAQ++q~&_on}izLC+P%(W<_kp;WYwVoS_Zavc$-KP0@feYI!v1AUr0I4 zd9{YOYioN&L^)WcUj+ImhlcilwUcabeD6}?uztb+bop(uH6|th?g-bIsQ>(8DP)da zdKczAgq-egO^7ezXGFHJhev#_>AepBO3Hm3A@6v{@{x+{u*k`8{gp2$Uw$=*w}oSV zzC#7$V|tS7rWK1&_e$UK?F^QFDtUYThpk`k2HvaO|4oQ6BO##-j*_x0UIYzf&^ zMRZJjsKxxd&*ado9W+0@eDp{Jt%vB=?!I4ZK+~X#4deRpZw5W;uWUbbJecLi&u{CY z-Z8d61?SYijQi!<#t)*aOr+k<#j_KJOA$|zvPL{u=LXxk_ zaluWIt1iP)pfr##huceyRS`81Fp_C)7{);Gtu!??Ppq$tW#n3);=m^nD()RrQ&MsC zXvs?YypF3vdxNyOE&EmH6UY*7+C$gQ{$Y0eR&^Z>p%Wz_1KejnF!TC;+Viusw~R&T z@uxzBlSyMp9h^!hUrh9}%=L`#4>0gJBc+|Ctfi2s!gEp_8KZ-yO=S|31DB-+8MJzU@U$8;B2O3 zlo~5dJEk}Tcy0x&mHpsBA8d3EIZc^6*8PT=;PbP=QUzwxbT|*K|M1WdAs>PMM=?t2 z015HAKd@2x!=P64MHNxh1I4bUBxB zPfcXv-N@snn;*VM-e_oI>1l>W3Y)mDDJ-kAEyq0%PxeX=*rldgj!ia6#jBhyD`+-! z5>q4X=~yWycqbhKq9ZU)jbxwr{@o9yxHOfXC!EB2AhQ^*}>Hf(Vxu$Q8(1XRxg4*CmiBAU8|SzB#`K+wv7z zFhhw{P1p-(ia549^o)P@np&UA8?20C#LE-%Q_WklpR3cSrMHSWjP1t7Es8V4^~Wy# zSs+CsKGDoTvnobiM)vZ2s2G#m$J}q{d83s`(vFT5&9Yk06zA2a7X7tHp9ZnGO-kOKrobs(=)_eI3 z%EQliZzVm6O$$H3zwNRoW5lsL>nGYXy4_UpsISlyn_Uc!mmG;bV*3rx7M?%pHkP4uSL{6|tsBS>1KFWANmjy(vXQ|HBrg18!4rWYl&RWLCZ|8gl)KJ(8 z6T}4Uy~(#?btns1k?S6APS zXEd+!r4z2SnY-JPcP&#EBx!p`gKdMbDkMFEP5bAvpRpm5?Jnn@O3q=Ezmksb<+0nV zC!E3kN?5>mGQtGgdiJ>{Lx^8Jv!Hp_ytuINR*-e~D!uhcOB2DYZU7Px=7fkNx>fjH z5gL4n>13jo8wq$`M`Av$xveej`%FD^>(Yge&Vd0R+>KC4OyA{-{VIUyqly0axt>dh zrmrvk@K$A=03#!Qbi2rFR}ypcz9#6)l3YZc1GjRV(ckB|)V!~nhvfL1vZXL=iC-p2 zVmroqG!jXOw3>LphW{nvaJDKJ8+z3HKvn35ACXYx5QiM$?*bEcbGXl7twQh^{Pro2 zK>qq3Hw3WC{-J8LS&9C4ASBR-Euhy{zSU39=Fvu~r|=?51=8Rf=${~!9<6LL=HCF` z4g!1xtvbEtgp2oOrb{=GoUHno&Vb@@%6R_`3|lfNtBVHoZuA8+nL4wx+L=2)vcA= z9t=|!=F{e4=GSvbw;P%KJjx_@dhTf%IkEIo(|nlcwdaoySj8NLzLgGei*tnw14H=^ z?^6RVV624$>xT%iq~=+{fpqFXTKY^+6wGb?;VC2hYeVCkrm1sGsnY974()4&G}g0O zUj=sTAUF^RR#K31SZqh?&OUW7yz4=ni21)ERyWpr&><_uKi#rQhq+~5Fr=xPu;*dzlE>>1W$0+!&MRzlx#1BUq5_%=!IrU zXCN`S=WrZib~pu%Im%I6l@|FGaMtwMkz%+&FzUbk{U-}vA|~_wYQlTO8xZEr1xQr~ z3g5{^o?b)D;Ut(V9ZcW-`$bY%F8$4{F3}rml)dL8Nk?9vd$s$*n~i8}MCKd-j7#w~Q%wu=v{?XWBXQAMB!BrV?yzJiw)LL*9RTiX zZ3S;*!xK=CVBhm-pRx~Tq)k_!{{DMBcjD}so123KcU+d*TN#xPQoqXXe`#2_FuR@n zb-^T8yZ`(B{kOs61|cy8Gky`VUpLmebrBX0kL&g0g?_u+{`yPc_iT7~p5ZJON=z_o z3dQ!IzQyC$_X?K3<6x1xFxw^J1c4Y9@2%m9|6Z^i3!|0{90GK(f6QX=QF<#^&-kxX zrmo8&g41cT;UZSfm+J)Zz)>9`+rY!*5RtQ<(*X@8FyUvACjX8JxBC<;KX-w!1R>73 znIYg5!Ke=CTcHJ6Pp@587hjA=JNuSe84qZ@v$xK-!?FiZe?B6Eu<2q7D*Y?q8ON49 zm`M;d!EkPcD7-m9{VAq~Y4^s#{C%2Rx8EueZ@%nK|#>mTx@@o-w1T zt(qkbErJxfh4u1ed37=M8tSknUC_~jpzVk4Ggti|7;b!ClD^8FyI!pY%BKos3SY{E z@QO~f=sq$#-}r25@%d^m->&t_i~t01RLorfA_(b@ZSmaXT};@m@MQ-*pID{h$fuvw z0Qdm6yr-eUugbWSeQD>7$kVwVSkJw1u4ZQ7!v|bSIqil~`Wb)wJ60>ZXzY zzPnITcSrf41FP$uJjq>KH^g(K2*}ocDwO5yW~&VIuwM7c)bn!1Em?aX=NHG%FtoI` zWEb;rjkeA+?$L-kOxiQN=L7Ti2aFS$S*~lBdWdYy2UO8FH&N1*b7w8*$_4)5?d}kj zM=|KCtaWd5SBu5%_s>VY*lP6|0-YhubTC1>Pb>uZ{kyHkHH4mA0jNI-jRxTY#WEm* zTntPsMc8@uQ9;@_B~!rXAoOAIFIk?2zJypdL-4%}I~UfcK(C3_9^RUBSOz1tGY8lD zul|sw`8K0w!De~L#hh72gejnK!@98uC$uam42GYd(kx7ulVPZ0mpBhQ?`3~-b9c2n zG%ZXdP-0oniK(dpln|P&)ZThafYgj_%C~_FRHfnoGwS9(_V&_0_9nbpb|kH;Zr!FW zCkjgLJ9#UZ5`)ZcO^X#6tU@h3i7(#6*D+f9-wx-!X|QJl0*7Y zGg=|~Nin2Si>)HRz}*KxFsy%#FOX>qEV8J~p`jN!v_(Zl-)G3n%A!}|tg>;%2pB+Y zZ{TW5eNq)BZ`x%G>pe7Y{Zg|=!wpX&<)x%(vWkm~TdY&UZOUt%zIJcmRXoHKAp7a9 z&olD*1*dxtACB$oe)%clkFye4nOsjbNmu+UPG>y2>rZJLZtS677?lV!=r2eJuCaFe zcIKkdfLdWyqvqu6)V^s$1~&fr`)^p@jGRq!j|4B^dfB3Lu;hRyYTe>&Fjzm)wKM6Z zlbq$5_l(wQ_wLF2P|ap}v-RT}u6fl2XQbZOW=hFZU>ccuurrn^CczdlRfLin35Wz9 zhKH2^plysbySjR2^244WQb5*fnrhIX0q@`YMlwRHjMsT6OL4hqQ1=})J(#@7D!yq> z^U;WE(>D95c6CRxMN+P4_4rYTgMGw0f?3`2eggaV+PbAd%X#}gar;CIpDYPv67L_| zBR|`_3UFz9^lt~tz=PPW<5e(n{HJg?f1Y>r16%-J*hIe(hwkb#n0Wj7>dnso!fE@c zP^EeNo2|#hA1r8*ojI77)=h&Oekq(z zWioXS2grQu(e%Xjt8lMl#S8vjqoq<~`wU{tJ4*bR^UW=6X|nVS=Q%u2tzy6?!m1@} zIW=<)Emw1Q*A=o|G<#cN6dxER6<~*gL zqWt0gfbCAyqNM$U@xgy@OX-hL@AOOEk#C9rT#gb13BVU^OLwPo-wp9m0h*qUar!^D ze!r)2&x}J$mCod2OiEf`ezJX9oPCe}!FkJdlj{e*4JZViIw{_2KI`+>c7Ogm7>;W? z>KEI#o#g-8?oa);-Ji8zKVj)ea7J);KY^V0#i^#*q(4s>08hHs{q;83XgqKQG5BRk zX<2?oCVAPBzZU!&47)EuRFZu@&Blbt9_UiZ(Y*Wp7l8X)C)b|ohqrCV32j&tl+m|j z9)@)zK--?*VAug8n6MVYN6@mq>FH58H!_*K|E?=BuyAU!2JS6~)gsI~Dw^d(SXPL1^|gl`SO5yloM=6x zwE2T(^KU=N2-@iS@t&$!c|*fU#ZKtZ1>hN+HPp8Lpr`gu#=pNnsUq~ri6k2}M;7dB#mYJLW4;uaM2Gs2}T^EvwK zQ`<9N5i{iChuq8m_`m-$ao>RXaq&}kv`YTJ$G@IF(o4fFZr8P$UhdS`-tzUt*NSs- z1T~^pzSNk%t)=^RELkeu(?9DkPDC)v<9|*e!GIC&r2H?zp5Lb@3_}LJW;_4zi=^al zar@ZeIlPl|*SXAdo1EsPTU+1Uo3l|luo?S<_L6QSbH8j;e*a3uF*Vq$r?>$!EN zm}-{@J4HxRF}uSvkHt%V;N8Ae{wcGLqI|u4pWfAg5_jnbJLSNx4Oq%QDcR-2I=f}z z>*d`oZM}Vw|6Hn1g^%1*Wa&HAKa?d&^*R}}A99b3Ju+Z%$Dd0fM(6VWfB>e{`>Wlx zVN?l%)gy+tCAX~>0Ez$ea=cjM-!FDAY;42z7(S?^&ZxMKn{Mf#PVQ;>GuDftzm|+= zSur;FS$z>^q>mmAX)&Z%u>IE5X3VelJ@@6BH-=AS96Wv=+@zwMjc?Q~52|(@dug3{ zh`C_iJT-4m@KNo`enx!G#Z!KnKM@1`X|bb0fh_S^K0c8L6uLc<*-1I}XTgo)}Q!y|&Qow1+5LpBY zqV8&y%}%rBqO?q6R}Z7cb+IixQEmU&xayvp+qpD36Zd=Ny|W8my}JBqpI<7lH`-eX zZ}#-N=}ynn?;Q|K`6K^jRbFS!LWt1l(8Ne<$9ArHp727inzwA`Kd*gz$4tFfDYu~G zgs4>`IjluDZ+MzAAJE@fpf;^PzI9@5Y(w#8XSc#-p{(|kd(OTke+@3Li|-og9d1h( zH{Fl-YUg&I>tQb9t`tgGh0e@$^Y;1%vE7QP8zly+kD9wr$a&`0tZv&n70E!yWC;!paH#Lx~42pw_|G_f)7iYIj&(b!x_T2ESx#ga=uawVc zNx@GpK;Yrd@i<)-iUm7GEA@#18N0=J&*^X;?4oPT}( zy41qtR)g}8HWeAKQ#Nxe+@P#W zV0HMzjEiCKqkU(pP90yha<}5nuGRv|_%?yBnI_vX?aYVMJ$RawSE-b+xy1-@m(byg%LB{F0)2XsY8bv7n+w!`_VUh3p9RU zi-(`Bu+8dlr`vZ$zos6jOEiPEx-q|gnUiOpY@kAlG+$^>g+B;{b#-;NKR(r&QLKvR ztJEkiOZ!ExJy)MTa$_r>cI(SR^6d64EAWk8T^!wf-tpuI6UQ5>*(;A7`svGi~zosfi9*-qEr|w?p z<@o1mT{2ysBX~b3?xM*PZbVSn+1cHo3D^=)Vow$qquv@-Dd!BB9&mj5D*QT)S-O~K zx&Ohoph&(C{q?sa!W_SZYE9epuW<8bI$qG$P?O+j7OJbA3U-)4n99zsN1n_Z#u>}PXfgi2fj68j z=t7&LDzBPpu_OczG=yEk&_L(0(qPDwYs7JOITk5bBsvL)cD_+rm-#DfXqY;>BNn7# zbxguh>u08PVi>%#H4$yhaN|S&a5$_Xvks>Vw!R~?7&Pg z1zADxyEbfmDd-oePCm9QbW^ai+ZjY@D(D;(z~+=kCUDl)vB|Qd zNCA3Ewa_z1b93{To{iHvaZH#t-lR*;m_I0E&b_~`o0+*}$e+D?eoA-Dc|^*_q@l#> z=89TaAWiJoJ?YaN#N}V{)Wvz;Y~(!efz2dw)giM))4II6L*a2hn%KaE$$O{pB2L{z zAgHvjHs0Uj#mSCp2`(;CDjk>Tq21+enoa{3L&^G=Lh~0Z*dG6bTKeCE?U(Tx9x2^g zNn_WWArvfT>r*Z<%@{@=;gVYzq+>fc#Yl?v-f}{ck}1mi{kDdhKzw_JyzAT9qO{S* z2qXVf7l&GCm+=|j?^02Y*~w#*y))I;F_=$l!QHm;$0-LV#f;7;lk&5l%yi1Qh_I|V;{W*%m-@^Nb=G|KN%P4e z2e*e@udh1HnKs#)s}7%Jv#OYcN%EU=ML?KC z;qz4@c$>Ct3Bb$8Dq$QmEsYd91Xj0%HKoY0KA66Knk7JgE z&zW9*G7o~S_c}IR9L&rKGAk+IH<%~8X;)Kg=(fcflyO^qH%_%)`$F=L&SA4!CePfW z>pu+X=niu3`op<>cQl*nQHPUT`GeL5l}cNVY~tnpnle%0!^uka>ZyFw+TD`pI`2F^ z*Lp%OKkvcg(6Xb~avg z>w1}2StBs7?i5n09~_2vr7FMK-6+pHS*trDFTOaLm|hTVDV{{3Kao_%?#`h5bs-~f zK8&pY*^}Is>+c?CU6*K_KlWo@@cO2r7Ok)T9+}ROXER0J@3G`&J-t}53ty04qx9aK z%kYkT`Oue_NA>MvuE;I$8_$OFN3-T}8{=Dl{$SB&++j8{!#wca`kk@Ykgrsj8=H4L%FxBdq^Q)kI5P z+;bZlb6pAGmo^L1F=VK|0+I!@neb+$4hgD?`sT4c1puFP<9fHky`&A2GEuK67#fORea!(-A(*UOxIY{#rbp z3%huAeiVxit9)OZFl;gWcENN5Ez~2H$9CX^*vT%o!Ru{Wm`I{oK0}@D*;qLim+H)$ ziT6HaSLX7O!x$i#DV$UzUuxfXJie%nB)fI_@GxiC1K-f=X=!Q4!;br!w~D<<(O7CD zIR*$O)OfKGb48Mk>EAKXcCfUi+@*y~|x4Uf(N)pRUH^3G9&o`sI#n z$p@vvp6&b@cUI3Lv+Gbm_eH6?h#cx@Uo&O6YJM(K^%XCN^c3lx`N#aJ>B}9SGRmGV zFL!cw7_pwp3#1Oz^-;Sy=W(Xx$p_24c( zcSz`u9QT^{*88+IQuU0=Kj?KE=c!f~ z(`?p8J%28Ung9_;hVX#=@~xu|U@z1pV(E3JUp1kx&OT(pyWc*#E4nl497nJJ@~En} zh03$br?b`vBk$OydQmkg%S4|8o+)+9ZWY7yyuIX03 z2zxrZy-IYSxanMk?LIf^$EgZBjqR>viwrban4K>!IQ^nYF~fd7;HcEidJ&4>p?8r9PvLs@NU5J#7CB^U|9m9ZQBrMs#v)n|vPxOG;a=FDz6( zEthGjn7Jc%){9;DRroH&q>1C0ndlZ~ek@I#Pxf9jJek@kRdIwL?!s$e<-l}&lVlg{4T2y4{PWiCBxcKlSeQftQ zPS;vVbN~~^)a`Xq$Z&9?jNcm(NFmePE(mu?gi9ovrLTa`r)Y-YblvNq84ZeGMRJ)~ zgj(^i_Im+KTiXaD6(*pkFHU%N))ajJ=lDGgb5PKaNNaMakid?b8SgLN7fWY=H7CZk z{Kzl5k$Xwlhs5x3Q}b}s`~--=%;aO=JNW8}vRIB+JBoxI-2_$0 z%`fA-PGsh2vB2e|EuK~(E8-6Wv5wk;xCY}RRDP2ubMsDHzsI^)RYn}pJyPRJvKeSB z&28eE8$R3{tdo+eQBoX~pPf2{B?`0H#2WvDnmXU>C--do<4Bv^QTqw5f_;a?ZXR8l zz2)$q!Cqry|6f~Q0Tt!e{XHrIA|W8%Dj`Tow@8bCG}7JOcSz|*u7GrRhjh0z5<_jcXwe^FD+kR#^7r)1Y%lBFvwgiPwQ~zs zujWfnww7yWVuH%Y*w+`o+k^wn zk{jN%ulIuz`wy6znXla4LtdDy+77LAcFRc17;J~dTh27bEPC<{o*xpZwdg$$1qKSd zj7j%Ryh1hz(B23&(y@oHP{WE5dy#=d+GIUt)2Mq>pIkNvGLJioD{#&+i+&!Ljz=qb zPF4F#@VU^OztgW)we7*Qyw)R$kB@B>3T&`V4*gBs>K%ZweRy2JktF2x>2Qm-9=wXzV8x@t}tYN_I z81s*c|J@^tg$?SpYe72h9cV82JvWv49{LUOLgc;cOZeX0U;Hyo1RdhxR2ye-((Ycq z%`dZRAV$UVW?3SI>^Dy2G4$`!OxQv9_)CywxbfOpuT*5Yq;k+WTYaM7)r~%nNI+BH z*l^4DiWr36+*TBlizy1BQi0m1uLw@RhmQ$Hy_PC1K`>NcB3Fx9(dP&0YxF)3ybr{lVjCdgYKH6CK^NI6I{h z%}1)LlbSuXd_ylya{T%U4h7LbY~c%;#HyvqID>QO=iOATOUz_Kc2mj+&)N?Kxhbrx zQv3yU0NShMMdwBB4{#iohWfu_|4!Pm+gx4Qx;$bN^{7H0-ZAe@d{4vQ)X18sRi^e@ zN=~|~zkxeGo=ELABJY7tQ7u+}ey=LUmTr5;*aHGpuJ?v9L%ou6m6P#(4K0UPQ1%4k zsvRB<HQQ)!V*;Pu=>Z6R znT~9NA-b>nIBJOd0UW%y9DiIS_2p6Gptv}cSS55l)&O5+XhVhP>#UXusEwYO$j4M- zeX>bCW624|Dc4kOpBbEA-5#u@DS{OpR;j-_;Rq-)k%mGEXc;-Cn`tIbTP8Lg!V42g z_Q+EJ0^Q3hyT3v$DJ|1hHf?`RYAqpOeE7?D4H!@Ffoie5vJ#><^?hKVbAH};Elc#W z+(l84wUjiYF!O=O^&mZnx%AMX{uw%&tT}uoD8~i*p^lCnf&!i!#q3t2gmPHJmRQ!n zuM)ksOCT?c)hAhR@4@J~x~*6|W}n2ce{*LB41HbXe=lntlUT*z0OdcBv`?ER0<8mtcDT^=~(_Lbr%yNQP z<)Y!lxS8dhC2iye<Hjz{ z-Q|`4X#SU;W5JvX=td9x_o|#yQgV{r`P|3G$jGmWCwJI)9=AbamTuY5LtiH*ZgV*g z5rol2OGcK$Bb*ieV?m~WSo4P$318yvPY8<~gyk)^N$wT|y!TPKXEX=lhIW0H%z6@f z&KG}08B{X`jY0MH7~Bi+1ls??~d~u)hJ+Hzu-HDiXq7I0_32j_^^U=WwJGi%_B$8)%?Yi>c;x zr2FS)N~mR6nG^+3rlLwuFe8z9@@FK+VoCl+kJQv+TYdSso)C~=1dHl#eZDz-f%9lZ zKNG$*grOGwy@>e^%D-f(m#^7u=iLbaPn&S^M9i-Ihr5#vc5GDCyi6&wD z6*p}q-q){R`-nYan3{?a=~aNSfKTPDCQ<)ThJJ4<@JD#P00HbHSCK>8$hW}n;sSSf z!N!idXZOE|_&`51O*P!zkjfddwj^?7no5(nK|L4{(y3ntJyi-cKQ6z5DF3DPL9u{f$I{idS>`~gO!OL1MiV;cpXDC=>PtXv{qq$WE0zn(sQnYzTJ zZd+?ih!cZCh-;@!vSC&QjSa8?WJhlTy_R@;JdA6j9MemAX>O7*J~b(LOE?WsIa@{|h3b1Gq)R zp2tNYhq$np^X}Y3ik6M3DmP~E$UmCogdF$BuzIDW{@Tcjl-oE5>4IM8+Z^xX1#z|9 zPDOU)8qyGxB4y{1LWetr3Z|ye#W7LOxv`tjQ>lNbnbH0}Q(WM-5|94m!Zq6Duem0a z-rkqIC`OVkOd6j!gm=)%0>stNxWquPoAq3Cvc-J-l7s2=fLt!z!-F_OeS)4hT>dkX z@Q0h;nW0=^5B6g#KXfVN2vWWXz04j;R#y4-8v|O;P!%#E5y$sobM{q{Hr{e4kF_46 zvaoUZH#9Kt&(G`W>u0djCPyYZy>}|oZXmDpydV<9AX(a^FkY@%mmX=5;EHCnD4g7v zu=_%B`VFz-ao5o>k7dktnNOq$H+q-5bG{JAe8<}l75zMfy9^8)q0=ri44ed|0hsdPHpYckDaSG`Fa z-P7g=Q;p6TeKRxPV;kz~x47`{*f!&>_fEz_wEkwYk>B%gfK!;MJc4qnSLJY%<{tnmV= zM6jY+?=QK-&lm;BZe&OdI=Osxt*uLBn%^;MREcvM^)I@e=)XzT-de1w=_5qOAn~VZ z7DN?vxi_rMAJ~w{&>c=3T$adHzTZkED&8!nwa*(z$W07`!64qD>0hzGdE%znN#^w_1^$UHF-O<+&gAs>+IM$CEp?6Ux*BuI2DkwzhO_~GaimZ z+gGoGKwR4Q^#(d^>MC1$W|aE@F6koe8sShSWfE3H7D1~; z{CUBBAH_hd?+J3-own!dgw14J#9r1jke=V`@Z++mAa~s0zZ{IIOxIsGhPZ}ve7t<| zqOoV3i0wzY7Rl~~!(-1R4zj@ncG$}kV^0}4&1;-Ua-k?jJ~C1t{G0f(g}Au5*4|!h z2V>cuoT|bf=~g6H++O!mT3lap4V5yeWXSAnsKIyMj{h!5+2P)fI6TpM+KjNK=e(-M z;pBu7@>t&oHaK2)Nm296_&a*kcS1fszivE89zn{gs>CXb60{oKKUUwoHKnuck8Z2^ zWFS8zSSdV{sR3z5KhvznfQX8VEpH^x+PXM&%)0ECIZhDIHR59CQ|fMqeLQpM(J5n6 zCU!EP5SyJ0)8BF|}R!I^lG8DL1u7lRu1<;IdP2oHZfCFOHM z!yq0PNmke9w!cE!7|@}dHNF}*<97bdo`u2NLNSfheSXF&%k&B1V@zv@e#HmNU;5RXy~qtT5d8 z_|SJ32~2#4%~Hz)#>3OC3S;xOem(-H|JHOd1CsEYNalw0M&AeY+2 zZ=nH5;qJs~hEfc!wROEIh7+;H#Te#pe=S=|8f$`Tg0-$MpAKFN4agzRO_GU|PiFUDlb2jg0zY1=OMK<&8Q*I#Nz`#>3tO=sc$_TQhpL+qnF)`!VtzU^kWRnEH zSiDj`p2$&|9;;b9J}*m#N!_=s+MP0sg&RUNEXr9_35nEaoC_VIdL)|6L!0!l|mt-re-AFK}i+*)if zF&=s%_av_NQcsU?7A2&ESP-Z=W_DX}DA~V3_OChWvXH*KPO=o^cYG12W>XQpD zr8s2(SDngl5}S_IQ`4&!1idyY`cY%z(ij@i)*pl#b1GnE54)Y$he~m$sp%R0&XG1c z11;hnxs65XlsgrX&W2ddJtOB10XkX-5&b;hzO#)f8#sVfJoCce)MP`&TipxU7z|rLb<>(Uz4?elHNsj zyIZqBNs60?ckQE#a&AXo0n)(0z`?c?62HLQ;hgNmH4@s*$lHmkydd67Qz!;^Gy{r* zgTo8j>?M%7`flH?exnGZTn)W+djh_)E{}bs}e5h7rR7*ib`$erefW ziqrLLYfs(T>|Z5Za%)Wrhzg0l)Ii(Xqh!3pY4 zJT3vePs^Ik{Jjw^WfvMYW$kh5JP zD)zroQu6Rr{$z-fG~B5qX)xZ%p*SJ1-%WKIG#p|;=(#g6FhBsrS_~KainSjMf$WTC z8!Bd~#U*-8$y2Jv97cy<`KyH)GTw}H^;x}fzTspE&ZJt$}dhciVxJw=( zgFM9s{G9isficqfE4y`vu9thsva2yK4KVg+s_f{wk=izyGd@O$UpHNzViQnAQu!jc z&rjgR;^WiL#DwJY4fV)b1uizBU~x@q&gN_A$e2?b3gD$o(#{6iGl`UC&Y; zKr=7CU?%n6yQiazX!Ei?UAX42k#`b$Nms8eU9jiIlmDf%u8t^0(5=KVDe3f^C2*VA z3k5DVV4W7V(2O|$t1(5u!l4k;$$Gqv!T4~RaQCMrH5CYq?sZ zJN52ve@00S*DJiwsSMpX@JAV zeS@|~@qkCaP$e6Oc)T$5YpJ&0_*w8&g%ygYb}eDQDgs&fb9;lcjFPQ$J77*0_g$oc zD>HJ=n;Qw(nNPbK-g=hS0NMgdntlWz{d@&a!Z}A*Q2A=v`tUE;g99pU#3i$A@}tmy`8zPWZw5+n(m5Z?J59T$W) zgm=&pwy$fP;AT!JbIt|tYNzfW$<*+kv;T@VMEKg25@vltW&yK#(?SL7@-q`R;|x6$w#r z!10d$_sItzM*Gl4Nfmn}g`hZEA3l#A_2QP<^{XT`*gn#z{&l;F8=EXltZ8wUd*a8+ zT+iwK0vAQZ#d&kyqjz43NmIE;S5_qLT3W^Q6zP(7IjQWs4_sNl1{P9?R|I(v?3Wjn z$TMMJ7k;ytP^by#am zr!z^yFo{I9t;ODGuGCTCe`qwOXvRl#ho_lIJS8B}GBkPSN$B|)ukbG-Ui4(V7=E<& zjsp!_`{R**wM}M!{cbFwbgdl~U_rfSHo)g9O%VvFOr#xPe1%Siw$5^E;_i)Or&ik} z+Vm`W+y#D1dhiO!%PA2)GJju{5dmz?dyr;~ogJ%z6-k{jg}Vp9##6Q&SB%Px?6y^h z^1fx#^aEai?eUUc<4R05zB^0p+4@vo?lXzc+c!s-UD97c9c}c*01RDy!>q5Yp$s=1 z_wR;_vj3maXlqF>*<0IM5aYA1T|_&oXIItwpv2%EHkU#ApYi^02<|@@cjT*}5&VDQ zI=%M8KOyW{qyS=DI|#mL_usrjUxOrhIJfh^FDo(lheA@Y{ye-=d(`HCJsl!Xt5Xga01${r~4XrhQu~*SC@EY=zrzE8dBmsa#&} z-;aiGx@nRm;{G6eLEm-HME?sfmA{7*ENU-Q`QO(lz3CJe|NJi7eh~U!6AcPN^Pc*S z`pC|X+vAD?;QoEFBqS_%j!ZC{41KBwDGKNfx?kiZ(ThLRyZvHimBu5v9z$2p>|C#D z`R((6zoege%JI|6^4D5T@6B+)U`t0&%R~1ojn+wxeb)s;4a2ENiy%Nv=o7#?-n^3B^*L3c?#OCTt-hKXm zZ|yIlEpy>l%k8Jl9U9PlQ}NSgjrh1*yt|BE{yt=BXY7e0jcjY49WIOWn(Y+GVP6U+ z998vzlJNSuD~}(t`9)e>Ty;HGDpr4JWMyU44=d5sPGkM!%aCtVoXJu>c>U2p%-66` zYwR)P;NrOD%xM~pkcdd{B3i2A*voP@f?=|KNg@6IiII$5rNO54t&xY=StNkiuB#I| z@6Sepq{jB?=|`(QVQ+sWaNL6^3E$NwFS!c2Z@s~cp_`$<>^dp0`Fa4WOyXPDqNqg=N7^GwhO}w z=6)B17Ka!2kwz1-xYAuEuy@BVJ>mDbAtm3lj^lPlF9C|Rz~$+x%$mmdWhaRuO_*<0 z6^MO%_X4NrV+}b_9V8U&aoj!DQbUG6j@7li>P)#tfj|(XJZM-hT$b9G8YT4>iC)@^ zb&)-j$HZeNjd$h%HlFG>`%fXy_@Ytq>xL~;h<9ZrE(n+l;1L=QRHFA+OX8`zp8o7` z_D#gi(Q*<$SV{^lR|jact$yX1%ep$47O>);=$~xmZkMSntgPMJRTg$HkI*)5Sa3It zjnACU--QwKk$YLIV;QUtj4=5HtjxBSm(^7ES9w)~YPs)|c*zXJ(M5Lf2eFCp{KvMQs<+jhv5KopYdOMj}Okem*$Lb9nq!S9b69R|V@1mX?UxeYt$_LC_ zSXTbiYPrRwN*K8y`|#C7FrfXKlcfnQ?G?WXK7ba1Q7AQV^V3ABR2{E`3Gep+bEyHS z7{gFp`ntfrzmSQBrdxgev*K1vVI035DFBG|;iKzk<_AxXw(z|lI(UhS2OxdP9c&F* zgz5MB*_n6M>kr!8q6LRuSNBv@sLRayVf>K-X6}^lqRT`rHTiR765=+UXEsWQTx64z zysvon|LpCqsCpSFi3T5Pd*J4FR|qmL(mmk!W3gG*ceGr@%$AOMn;C%dnX0!HpbGaO zz>KYRI3))>p+c;d8$tG=_#IyKOM`IFCbtzWM|SN-_h101Th8AQ(8!_spEgdBc7 z-WwDe`PFUO7}z%Q+4k9*mzz%keZ#^W&o0i=4151RaCDJ4E>MO*e*Pqyy6RDRPfQWi z7en8+FobEPQRP=x7jKDZLy&k!{F+VA$PJwP9qDwP@z@+X;jJ}Yak~UX#l?0suYuAJP26YF$x0S$^HqxegPJ&Sf!T;=hosyNR{q?{jY8OSvvkKr zdiGHEj*v>E`LkK7=dY(n7*v;57w>1@SO%f^aFr=wHuX4EoA%jM@-1< zL&C$mqE=~buQwP0C{4vngABTunH$Dl5>6DT^j0?a<@F6tWc!RdWLjYI)HT%IhbW9G ztj8Kneo!uA!lQpfAJf;BaQJpKpkP0z! zUU$?>m%Y{l8{}RAy@i6m*peRcpg_2BNqu4m6V1r&R2X#Er6WsVbbl7Yi??n2NBh%BFKL&vS7guHVg)7u^KDbLiEA8%YdP_;ag>xLvKYZr5u2#z6u~xd9FgEETJ@#MBr)fHoC9(Ilmp&;|kQp2w2Nt7* zphJl8)w=BqW*F#~Elp;Z)zpl+ zLc`C_kamTRuolF{ZaHhRy`-akjuadNJ~HvIO;=`75AhkhL%%WuG|CTv{o^5U17Q-* z70d5Do!#BfOgqG1&`_t>rKa}X&MuPI-Q7}yM59seedmyX8#WMz9X%1NZJ83pn~5?X zJ%m*19nAoEk0Ja-X#*_Q_S)w|wR#1-!t88n-fD}`RDxISK*Io?ue)Z#6P315 zv`_so{jiT42J+sTP|!s|?^yid#6mMkNmm3ptz4>bODRgGOzzNBB?97^aNT4Hjr{qA zwr!&8p>IIs+po-Sx;rN=pmk~~+z!~LfkuTY&(l;X=76kb`1;BxSZaeEQSe(8-?zl+ z>}(30>n!fyb%8*mKl(5PLn`CEefw6KlU75F| zm8-__^A9zHf{sSBhSh1fN^(At3V7n&$Rut*zf1GF)oKw)9-Kd&pz*u?s-+-0#N&(u zK4IbW@A#trF_JIdibIj#GAG5jQ59A9_f18|kRTA~j|K1jT_zI*0WT>rS<#ZWx<3C0 DL_u)W literal 16647 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 z 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 X(&m=bSmM8)CykuH%k3H*Nm3p52& diff --git a/gui/wxpython/gmodeler/g_gui_gmodeler_python_code.png b/gui/wxpython/gmodeler/g_gui_gmodeler_python_code.png index 77b3ea6bb91a0d7b23bfc225bc87445412be9bf0..77c28876d9c687d072c5b83c4b210f32c20d0ad4 100644 GIT binary patch literal 110861 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 literal 16854 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

    hrqi}-uDyfNzQ(*z=Z(O$I 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

    >@geERuaxi3raDF2TMGMO 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 A1^@s6 literal 13366 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

    GRASS logo -
    """ header_nopgm = """

    ${PGM}

    @@ -520,42 +519,90 @@ def escape_href(label): return label.replace(" ", "-").lower() -def write_toc(data): +def write_toc(data, hamburger_menu_toc=False): + """Write Table of Contents + + :param tuple data: parsed data from MyHTMLParser class instance + :param bool hamburger_menu_toc: write hamburger menu TOC for the + mobile, tablet screen + """ + if not data: return fd = sys.stdout - fd.write('
    \n') - fd.write('

    Table of contents

    \n') - fd.write('
      \n') + if hamburger_menu_toc: + fd.write(" +""" + ) + else: + fd.write("\n
    \n") + fd.write("
    \n") def update_toc(data): @@ -657,13 +704,20 @@ def get_addon_path(): ) if not re.search("", tmp_data, re.IGNORECASE): sys.stdout.write(header_tmpl.substitute(PGM=pgm, PGM_DESC=pgm_desc)) + if tmp_data: + header_logo_img_el = 'GRASS logo' for line in tmp_data.splitlines(True): # The cleanup happens on Makefile level too. if not re.search( "||
    ", line, re.IGNORECASE ): - sys.stdout.write(line) + if header_logo_img_el in line: + sys.stdout.write(line) + # create hamburger menu TOC + write_toc(create_toc(src_data), hamburger_menu_toc=True) + else: + sys.stdout.write(line) # create TOC write_toc(create_toc(src_data)) From 97349a760fbd09852a20f53b4954ff15b61d50ca Mon Sep 17 00:00:00 2001 From: Stefan Blumentrath Date: Mon, 24 Oct 2022 21:06:22 +0200 Subject: [PATCH 050/123] t.rast.univar / t.rast3d.univar: Add support for zones (#2588) * add support for zones * add support for zones * add test for zones * clean properly * add test for zones * add support for zones * add credits * add credits * add zones in manual * add check for zones map * black * use RasterRow context manager * fix zones existence test * try if centos fails because of context manager * fix indent * change import order * zones check for t.rast3d.univar * avoid RasterRow * avoid RasterRow * fix if * fix if * fix raster_info * fix raster_info * fix raster_info * fix raster_info * import as gs * import as gs and zones * string formating * clean test * add semantic labels * black * remove gscript * name tests * name tests * move parser, use kwargs * move parser, use kwargs, allow DCELL * Import tgis after parser * Import tgis after parser * Fix typo --- python/grass/temporal/univar_statistics.py | 122 ++++++++---- temporal/t.rast.univar/t.rast.univar.html | 9 +- temporal/t.rast.univar/t.rast.univar.py | 33 +++- .../testsuite/test_t_rast_univar.py | 177 +++++++++++++++--- temporal/t.rast3d.univar/t.rast3d.univar.html | 1 + temporal/t.rast3d.univar/t.rast3d.univar.py | 29 ++- .../testsuite/test_t_rast3d_univar.py | 56 +++++- 7 files changed, 349 insertions(+), 78 deletions(-) diff --git a/python/grass/temporal/univar_statistics.py b/python/grass/temporal/univar_statistics.py index 04ff3022210..bcb6bc6abe4 100755 --- a/python/grass/temporal/univar_statistics.py +++ b/python/grass/temporal/univar_statistics.py @@ -29,7 +29,15 @@ def print_gridded_dataset_univar_statistics( - type, input, output, where, extended, no_header=False, fs="|", rast_region=False + type, + input, + output, + where, + extended, + no_header=False, + fs="|", + rast_region=False, + zones=None, ): """Print univariate statistics for a space time raster or raster3d dataset @@ -43,8 +51,14 @@ def print_gridded_dataset_univar_statistics( :param rast_region: If set True ignore the current region settings and use the raster map regions for univar statistical calculation. Only available for strds. + :param zones: raster map with zones to calculate statistics for """ + stats_module = { + "strds": "r.univar", + "str3ds": "r3.univar", + }[type] + # We need a database interface dbif = SQLDatabaseInterfaceConnection() dbif.connect() @@ -54,9 +68,14 @@ def print_gridded_dataset_univar_statistics( if output is not None: out_file = open(output, "w") - rows = sp.get_registered_maps("id,start_time,end_time", where, "start_time", dbif) + strds_cols = ( + "id,start_time,end_time,semantic_label" + if type == "strds" + else "id,start_time,end_time" + ) + rows = sp.get_registered_maps(strds_cols, where, "start_time", dbif) - if not rows: + if not rows and rows != [""]: dbif.close() err = "Space time %(sp)s dataset <%(i)s> is empty" if where: @@ -66,40 +85,60 @@ def print_gridded_dataset_univar_statistics( ) if no_header is False: - string = "" - string += "id" + fs + "start" + fs + "end" + fs + "mean" + fs - string += "min" + fs + "max" + fs - string += "mean_of_abs" + fs + "stddev" + fs + "variance" + fs - string += "coeff_var" + fs + "sum" + fs + "null_cells" + fs + "cells" - string += fs + "non_null_cells" + cols = ( + ["id", "semantic_label", "start", "end"] + if type == "strds" + else ["id", "start", "end"] + ) + if zones: + cols.append("zone") + cols.extend( + [ + "mean", + "min", + "max", + "mean_of_abs", + "stddev", + "variance", + "coeff_var", + "sum", + "null_cells", + "cells", + "non_null_cells", + ] + ) if extended is True: - string += fs + "first_quartile" + fs + "median" + fs - string += "third_quartile" + fs + "percentile_90" + cols.extend(["first_quartile", "median", "third_quartile", "percentile_90"]) + string = fs.join(cols) if output is None: print(string) else: out_file.write(string + "\n") + flag = "g" + + if extended is True: + flag += "e" + if type == "strds" and rast_region is True: + flag += "r" + for row in rows: string = "" id = row["id"] start = row["start_time"] end = row["end_time"] + semantic_label = ( + "" + if type != "strds" or not row["semantic_label"] + else row["semantic_label"] + ) - flag = "g" - - if extended is True: - flag += "e" - if type == "strds" and rast_region is True: - flag += "r" - - if type == "strds": - stats = gscript.parse_command("r.univar", map=id, flags=flag) - elif type == "str3ds": - stats = gscript.parse_command("r3.univar", map=id, flags=flag) + univar_stats = gscript.read_command( + stats_module, map=id, flags=flag, zones=zones + ).rstrip() - if not stats: + if not univar_stats: if type == "strds": gscript.warning( _("Unable to get statistics for raster map " "<%s>") % id @@ -109,19 +148,36 @@ def print_gridded_dataset_univar_statistics( _("Unable to get statistics for 3d raster map" " <%s>") % id ) continue + eol = "" - string += str(id) + fs + str(start) + fs + str(end) - string += fs + str(stats["mean"]) + fs + str(stats["min"]) - string += fs + str(stats["max"]) + fs + str(stats["mean_of_abs"]) - string += fs + str(stats["stddev"]) + fs + str(stats["variance"]) - string += fs + str(stats["coeff_var"]) + fs + str(stats["sum"]) - string += fs + str(stats["null_cells"]) + fs + str(stats["cells"]) - string += fs + str(int(stats["cells"]) - int(stats["null_cells"])) - if extended is True: - string += fs + str(stats["first_quartile"]) + fs + str(stats["median"]) + for idx, stats_kv in enumerate(univar_stats.split(";")): + stats = gscript.utils.parse_key_val(stats_kv) string += ( - fs + str(stats["third_quartile"]) + fs + str(stats["percentile_90"]) + f"{id}{fs}{semantic_label}{fs}{start}{fs}{end}" + if type == "strds" + else f"{id}{fs}{start}{fs}{end}" ) + if zones: + if idx == 0: + zone = str(stats["zone"]) + string = "" + continue + string += f"{fs}{zone}" + if "zone" in stats: + zone = str(stats["zone"]) + eol = "\n" + else: + eol = "" + string += f'{fs}{stats["mean"]}{fs}{stats["min"]}' + string += f'{fs}{stats["max"]}{fs}{stats["mean_of_abs"]}' + string += f'{fs}{stats["stddev"]}{fs}{stats["variance"]}' + string += f'{fs}{stats["coeff_var"]}{fs}{stats["sum"]}' + string += f'{fs}{stats["null_cells"]}{fs}{stats["n"]}' + string += f'{fs}{stats["n"]}' + if extended is True: + string += f'{fs}{stats["first_quartile"]}{fs}{stats["median"]}' + string += f'{fs}{stats["third_quartile"]}{fs}{stats["percentile_90"]}' + string += eol if output is None: print(string) diff --git a/temporal/t.rast.univar/t.rast.univar.html b/temporal/t.rast.univar/t.rast.univar.html index 37ec56d2d5f..41b4e9527b5 100644 --- a/temporal/t.rast.univar/t.rast.univar.html +++ b/temporal/t.rast.univar/t.rast.univar.html @@ -7,10 +7,15 @@

    DESCRIPTION

    By default it returns the name of the map, the start and end date of dataset and the following values: mean, minimum and maximum vale, mean_of_abs, standard deviation, variance, coeff_var, number of null -cells, total number of cell. +cells, total number of cells.

    Using the e flag it can calculate also extended statistics: first quartile, median value, third quartile and percentile 90. +

    +If a zones raster map is provided, statistics are computed for +each zone (category) in that input raster map. The zones option +does not support Spatio-Temporal-Raster-Datasets (STRDS) but only a single, +static raster map.

    EXAMPLE

    @@ -32,8 +37,10 @@

    SEE ALSO

    t.create, t.info +t.create,

    AUTHOR

    Sören Gebbert, Thünen Institute of Climate-Smart Agriculture +Stefan Blumentrath, (Support for zones) diff --git a/temporal/t.rast.univar/t.rast.univar.py b/temporal/t.rast.univar/t.rast.univar.py index c7da2f4dec4..71f05213e1a 100755 --- a/temporal/t.rast.univar/t.rast.univar.py +++ b/temporal/t.rast.univar/t.rast.univar.py @@ -31,6 +31,12 @@ # %option G_OPT_STRDS_INPUT # %end +# %option G_OPT_R_INPUT +# % key: zones +# % description: Raster map used for zoning, must be of type CELL +# % required: no +# %end + # %option G_OPT_F_OUTPUT # % required: no # %end @@ -60,24 +66,27 @@ # % guisection: Formatting # %end -import grass.script as grass - +import grass.script as gs ############################################################################ def main(): + # Get the options and flags + options, flags = gs.parser() + # lazy imports import grass.temporal as tgis - # Get the options + # Define variables input = options["input"] + zones = options["zones"] output = options["output"] where = options["where"] extended = flags["e"] no_header = flags["u"] rast_region = bool(flags["r"]) - separator = grass.separator(options["separator"]) + separator = gs.separator(options["separator"]) # Make sure the temporal database exists tgis.init() @@ -87,11 +96,23 @@ def main(): if output == "-": output = None + # Check if zones map exists and is of type CELL + if zones: + if gs.raster.raster_info(zones)["datatype"] != "CELL": + gs.fatal(_("Zoning raster must be of type CELL")) + tgis.print_gridded_dataset_univar_statistics( - "strds", input, output, where, extended, no_header, separator, rast_region + "strds", + input, + output, + where, + extended, + no_header=no_header, + fs=separator, + rast_region=rast_region, + zones=zones, ) if __name__ == "__main__": - options, flags = grass.parser() main() diff --git a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py index 6c886a2e276..946a9a1152b 100644 --- a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py +++ b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py @@ -19,11 +19,37 @@ def setUpClass(cls): cls.use_temp_region() cls.runModule("g.region", s=0, n=80, w=0, e=120, b=0, t=50, res=1, res3=1) + cls.runModule( + "r.mapcalc", + expression="zones = int(if(row() <= 5, 1, if(row() >= 20, 3, 2)))", + overwrite=True, + ) + cls.runModule("r.mapcalc", expression="a_1 = 100", overwrite=True) cls.runModule("r.mapcalc", expression="a_2 = 200", overwrite=True) cls.runModule("r.mapcalc", expression="a_3 = 300", overwrite=True) cls.runModule("r.mapcalc", expression="a_4 = 400", overwrite=True) + cls.runModule("r.mapcalc", expression="b_1 = 110", overwrite=True) + cls.runModule("r.mapcalc", expression="b_2 = 220", overwrite=True) + cls.runModule("r.mapcalc", expression="b_3 = 330", overwrite=True) + cls.runModule("r.mapcalc", expression="b_4 = 440", overwrite=True) + + cls.runModule("r.mapcalc", expression="c_1 = 111", overwrite=True) + cls.runModule("r.mapcalc", expression="c_2 = 222", overwrite=True) + cls.runModule("r.mapcalc", expression="c_3 = 333", overwrite=True) + cls.runModule("r.mapcalc", expression="c_4 = 444", overwrite=True) + + cls.runModule("r.support", map="b_1", semantic_label="S2_B1", overwrite=True) + cls.runModule("r.support", map="b_2", semantic_label="S2_B1", overwrite=True) + cls.runModule("r.support", map="b_3", semantic_label="S2_B1", overwrite=True) + cls.runModule("r.support", map="b_4", semantic_label="S2_B1", overwrite=True) + + cls.runModule("r.support", map="c_1", semantic_label="S2_C1", overwrite=True) + cls.runModule("r.support", map="c_2", semantic_label="S2_C1", overwrite=True) + cls.runModule("r.support", map="c_3", semantic_label="S2_C1", overwrite=True) + cls.runModule("r.support", map="c_4", semantic_label="S2_C1", overwrite=True) + cls.runModule( "t.create", type="strds", @@ -33,6 +59,15 @@ def setUpClass(cls): description="A test", overwrite=True, ) + cls.runModule( + "t.create", + type="strds", + temporaltype="absolute", + output="B", + title="B test", + description="B test", + overwrite=True, + ) cls.runModule( "t.register", flags="i", @@ -43,14 +78,37 @@ def setUpClass(cls): increment="3 months", overwrite=True, ) + cls.runModule( + "t.register", + flags="i", + type="raster", + input="B", + maps="b_1,b_2,b_3,b_4", + start="2001-01-01", + increment="3 months", + overwrite=True, + ) + cls.runModule( + "t.register", + flags="i", + type="raster", + input="B", + maps="c_1,c_2,c_3,c_4", + start="2001-01-01", + increment="3 months", + overwrite=True, + ) @classmethod def tearDownClass(cls): """Remove the temporary region""" cls.runModule("t.remove", flags="df", type="strds", inputs="A") + cls.runModule("t.remove", flags="df", type="strds", inputs="B") + cls.runModule("g.remove", flags="f", type="raster", name="zones") + cls.del_temp_region() - def test_1(self): + def test_with_all_maps(self): t_rast_univar = SimpleModule( "t.rast.univar", @@ -62,11 +120,11 @@ def test_1(self): self.runModule("g.region", res=1) self.assertModule(t_rast_univar) - univar_text = """id|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells -a_1@testing|2001-01-01 00:00:00|2001-04-01 00:00:00|100|100|100|100|0|0|0|960000|0|9600|9600 -a_2@testing|2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|1920000|0|9600|9600 -a_3@testing|2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 -a_4@testing|2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 + univar_text = """id|semantic_label|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells +a_1@testing||2001-01-01 00:00:00|2001-04-01 00:00:00|100|100|100|100|0|0|0|960000|0|9600|9600 +a_2@testing||2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|1920000|0|9600|9600 +a_3@testing||2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 +a_4@testing||2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 """ for ref, res in zip( univar_text.split("\n"), t_rast_univar.outputs.stdout.split("\n") @@ -76,7 +134,7 @@ def test_1(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) - def test_2(self): + def test_with_subset_of_maps(self): t_rast_univar = SimpleModule( "t.rast.univar", @@ -88,10 +146,10 @@ def test_2(self): self.runModule("g.region", res=1) self.assertModule(t_rast_univar) - univar_text = """id|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells -a_2@testing|2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|1920000|0|9600|9600 -a_3@testing|2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 -a_4@testing|2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 + univar_text = """id|semantic_label|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells +a_2@testing||2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|1920000|0|9600|9600 +a_3@testing||2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 +a_4@testing||2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 """ for ref, res in zip( univar_text.split("\n"), t_rast_univar.outputs.stdout.split("\n") @@ -101,7 +159,7 @@ def test_2(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) - def test_3(self): + def test_coarser_resolution(self): t_rast_univar = SimpleModule( "t.rast.univar", @@ -113,10 +171,10 @@ def test_3(self): self.runModule("g.region", res=10) self.assertModule(t_rast_univar) - univar_text = """id|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells -a_2@testing|2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|19200|0|96|96 -a_3@testing|2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|28800|0|96|96 -a_4@testing|2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|38400|0|96|96 + univar_text = """id|semantic_label|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells +a_2@testing||2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|19200|0|96|96 +a_3@testing||2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|28800|0|96|96 +a_4@testing||2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|38400|0|96|96 """ for ref, res in zip( univar_text.split("\n"), t_rast_univar.outputs.stdout.split("\n") @@ -126,7 +184,7 @@ def test_3(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) - def test_4(self): + def test_subset_with_output(self): self.runModule("g.region", res=10) self.assertModule( @@ -139,10 +197,10 @@ def test_4(self): verbose=True, ) - univar_text = """id|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells -a_2@testing|2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|1920000|0|9600|9600 -a_3@testing|2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 -a_4@testing|2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 + univar_text = """id|semantic_label|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells +a_2@testing||2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|1920000|0|9600|9600 +a_3@testing||2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 +a_4@testing||2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 """ univar_output = open("univar_output.txt", "r").read() @@ -154,7 +212,7 @@ def test_4(self): print(type(res_line)) self.assertLooksLike(ref_line, res_line) - def test_5(self): + def test_subset_with_output_coarse_resolution(self): self.runModule("g.region", res=10) self.assertModule( @@ -167,9 +225,9 @@ def test_5(self): verbose=True, ) - univar_text = """a_2@testing|2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|1920000|0|9600|9600 -a_3@testing|2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 -a_4@testing|2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 + univar_text = """a_2@testing||2001-04-01 00:00:00|2001-07-01 00:00:00|200|200|200|200|0|0|0|1920000|0|9600|9600 +a_3@testing||2001-07-01 00:00:00|2001-10-01 00:00:00|300|300|300|300|0|0|0|2880000|0|9600|9600 +a_4@testing||2001-10-01 00:00:00|2002-01-01 00:00:00|400|400|400|400|0|0|0|3840000|0|9600|9600 """ univar_output = open("univar_output.txt", "r").read() @@ -179,7 +237,7 @@ def test_5(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) - def test_6_error_handling_empty_strds(self): + def test_error_handling_empty_strds(self): # Empty strds self.assertModuleFail( "t.rast.univar", @@ -190,10 +248,75 @@ def test_6_error_handling_empty_strds(self): verbose=True, ) - def test_7_error_handling_no_input(self): + def test_error_handling_no_input(self): # No input self.assertModuleFail("t.rast.univar", output="out.txt") + def test_with_zones(self): + """Test use of zones""" + + t_rast_univar = SimpleModule( + "t.rast.univar", + input="A", + where="start_time >= '2001-01-01'", + zones="zones", + overwrite=True, + verbose=True, + ) + self.runModule("g.region", res=1) + self.assertModule(t_rast_univar) + + print(t_rast_univar.outputs.stdout.split("\n")) + + univar_text = """id|semantic_label|start|end|zone|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells +a_1@PERMANENT||2001-01-01 00:00:00|2001-04-01 00:00:00|1|100|100|100|100|0|0|0|60000|0|600|600 +a_1@PERMANENT||2001-01-01 00:00:00|2001-04-01 00:00:00|2|100|100|100|100|0|0|0|168000|0|1680|1680 +a_1@PERMANENT||2001-01-01 00:00:00|2001-04-01 00:00:00|3|100|100|100|100|0|0|0|732000|0|7320|7320 +a_2@PERMANENT||2001-04-01 00:00:00|2001-07-01 00:00:00|1|200|200|200|200|0|0|0|120000|0|600|600 +a_2@PERMANENT||2001-04-01 00:00:00|2001-07-01 00:00:00|2|200|200|200|200|0|0|0|336000|0|1680|1680 +a_2@PERMANENT||2001-04-01 00:00:00|2001-07-01 00:00:00|3|200|200|200|200|0|0|0|1464000|0|7320|7320 +a_3@PERMANENT||2001-07-01 00:00:00|2001-10-01 00:00:00|1|300|300|300|300|0|0|0|180000|0|600|600 +a_3@PERMANENT||2001-07-01 00:00:00|2001-10-01 00:00:00|2|300|300|300|300|0|0|0|504000|0|1680|1680 +a_3@PERMANENT||2001-07-01 00:00:00|2001-10-01 00:00:00|3|300|300|300|300|0|0|0|2196000|0|7320|7320 +a_4@PERMANENT||2001-10-01 00:00:00|2002-01-01 00:00:00|1|400|400|400|400|0|0|0|240000|0|600|600 +a_4@PERMANENT||2001-10-01 00:00:00|2002-01-01 00:00:00|2|400|400|400|400|0|0|0|672000|0|1680|1680 +a_4@PERMANENT||2001-10-01 00:00:00|2002-01-01 00:00:00|3|400|400|400|400|0|0|0|2928000|0|7320|7320 +""" + + for ref, res in zip( + univar_text.split("\n"), t_rast_univar.outputs.stdout.split("\n") + ): + if ref and res: + ref_line = ref.split("|", 1)[1] + res_line = res.split("|", 1)[1] + self.assertLooksLike(ref_line, res_line) + + def test_with_semantic_label(self): + """Test semantic labels""" + t_rast_univar = SimpleModule( + "t.rast.univar", + input="B.S2_B1", + where="start_time >= '2001-01-01'", + overwrite=True, + verbose=True, + ) + self.runModule("g.region", res=1) + self.assertModule(t_rast_univar) + + univar_text = """id|semantic_label|start|end|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells +b_1@PERMANENT|S2_B1|2001-01-01 00:00:00|2001-04-01 00:00:00|110|110|110|110|0|0|0|1056000|0|9600|9600 +b_2@PERMANENT|S2_B1|2001-04-01 00:00:00|2001-07-01 00:00:00|220|220|220|220|0|0|0|2112000|0|9600|9600 +b_3@PERMANENT|S2_B1|2001-07-01 00:00:00|2001-10-01 00:00:00|330|330|330|330|0|0|0|3168000|0|9600|9600 +b_4@PERMANENT|S2_B1|2001-10-01 00:00:00|2002-01-01 00:00:00|440|440|440|440|0|0|0|4224000|0|9600|9600 +""" + for ref, res in zip( + univar_text.split("\n"), t_rast_univar.outputs.stdout.split("\n") + ): + if ref and res: + ref_line = ref.split("|", 1)[1] + res_line = res.split("|", 1)[1] + self.assertLooksLike(ref_line, res_line) + if __name__ == "__main__": from grass.gunittest.main import test diff --git a/temporal/t.rast3d.univar/t.rast3d.univar.html b/temporal/t.rast3d.univar/t.rast3d.univar.html index 9144911ea37..42a59843f85 100644 --- a/temporal/t.rast3d.univar/t.rast3d.univar.html +++ b/temporal/t.rast3d.univar/t.rast3d.univar.html @@ -16,3 +16,4 @@

    SEE ALSO

    AUTHOR

    Sören Gebbert, Thünen Institute of Climate-Smart Agriculture +Stefan Blumentrath, (Support for zones) diff --git a/temporal/t.rast3d.univar/t.rast3d.univar.py b/temporal/t.rast3d.univar/t.rast3d.univar.py index 9a228d1234b..c3ad1503b0e 100755 --- a/temporal/t.rast3d.univar/t.rast3d.univar.py +++ b/temporal/t.rast3d.univar/t.rast3d.univar.py @@ -33,6 +33,13 @@ # %option G_OPT_STR3DS_INPUT # %end +# %option G_OPT_R_INPUT +# % key: zones +# % label: Raster map withh zones to compute statistics for +# % description: Raster map withh zones to compute statistics for (needs to be CELL) +# % required: no +# %end + # %option G_OPT_F_OUTPUT # % required: no # %end @@ -57,23 +64,27 @@ # % guisection: Formatting # %end -import grass.script as grass +import grass.script as gs ############################################################################ def main(): + # Get the options + options, flags = gs.parser() + # lazy imports import grass.temporal as tgis - # Get the options + # Define variables input = options["input"] + zones = options["zones"] output = options["output"] where = options["where"] extended = flags["e"] no_header = flags["s"] - separator = grass.separator(options["separator"]) + separator = gs.separator(options["separator"]) # Make sure the temporal database exists tgis.init() @@ -83,11 +94,19 @@ def main(): if output == "-": output = None + # Check if zones map exists and is of type CELL tgis.print_gridded_dataset_univar_statistics( - "str3ds", input, output, where, extended, no_header, separator + "str3ds", + input, + output, + where, + extended, + no_header=no_header, + fs=separator, + rast_region=False, + zones=zones, ) if __name__ == "__main__": - options, flags = grass.parser() main() diff --git a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py index e9b0e9afc65..df823f73d48 100644 --- a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py +++ b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py @@ -19,6 +19,12 @@ def setUpClass(cls): cls.use_temp_region() cls.runModule("g.region", s=0, n=80, w=0, e=120, b=0, t=50, res=1, res3=1) + cls.runModule( + "r3.mapcalc", + expression="zones = int(if(row() <= 5, 1, if(row() >= 20, 3, 2)))", + overwrite=True, + ) + cls.runModule("r3.mapcalc", expression="a_1 = 100", overwrite=True) cls.runModule("r3.mapcalc", expression="a_2 = 200", overwrite=True) cls.runModule("r3.mapcalc", expression="a_3 = 300", overwrite=True) @@ -48,9 +54,10 @@ def setUpClass(cls): def tearDownClass(cls): """Remove the temporary region""" cls.runModule("t.remove", flags="df", type="str3ds", inputs="A") + cls.runModule("g.remove", flags="f", type="raster_3d", name="zones") cls.del_temp_region() - def test_1(self): + def test_with_all_maps(self): t_rast3d_univar = SimpleModule( "t.rast3d.univar", @@ -75,7 +82,7 @@ def test_1(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) - def test_2(self): + def test_with_subset_of_maps(self): t_rast3d_univar = SimpleModule( "t.rast3d.univar", @@ -99,7 +106,7 @@ def test_2(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) - def test_3(self): + def test_subset_with_output(self): self.assertModule( "t.rast3d.univar", @@ -123,7 +130,7 @@ def test_3(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) - def test_4(self): + def test_subset_with_output_no_header(self): self.assertModule( "t.rast3d.univar", @@ -147,7 +154,7 @@ def test_4(self): res_line = res.split("|", 1)[1] self.assertLooksLike(ref_line, res_line) - def test_5_error_handling_empty_strds(self): + def test_error_handling_empty_strds(self): # Empty str3ds self.assertModuleFail( "t.rast3d.univar", @@ -158,10 +165,47 @@ def test_5_error_handling_empty_strds(self): verbose=True, ) - def test_6_error_handling_no_input(self): + def test_error_handling_no_input(self): # No input self.assertModuleFail("t.rast3d.univar", output="out.txt") + def test_with_zones(self): + """Test use of zones""" + + t_rast_univar_zones = SimpleModule( + "t.rast3d.univar", + input="A", + where="start_time >= '2001-01-01'", + zones="zones", + overwrite=True, + verbose=True, + ) + self.runModule("g.region", res=1) + self.assertModule(t_rast_univar_zones) + + univar_text = """id|start|end|zone|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells +a_1@PERMANENT|2001-01-01 00:00:00|2001-04-01 00:00:00|1|100|100|100|100|0|0|0|3000000|0|30000|30000 +a_1@PERMANENT|2001-01-01 00:00:00|2001-04-01 00:00:00|2|100|100|100|100|0|0|0|8400000|0|84000|84000 +a_1@PERMANENT|2001-01-01 00:00:00|2001-04-01 00:00:00|3|100|100|100|100|0|0|0|36600000|0|366000|366000 +a_2@PERMANENT|2001-04-01 00:00:00|2001-07-01 00:00:00|1|200|200|200|200|0|0|0|6000000|0|30000|30000 +a_2@PERMANENT|2001-04-01 00:00:00|2001-07-01 00:00:00|2|200|200|200|200|0|0|0|16800000|0|84000|84000 +a_2@PERMANENT|2001-04-01 00:00:00|2001-07-01 00:00:00|3|200|200|200|200|0|0|0|73200000|0|366000|366000 +a_3@PERMANENT|2001-07-01 00:00:00|2001-10-01 00:00:00|1|300|300|300|300|0|0|0|9000000|0|30000|30000 +a_3@PERMANENT|2001-07-01 00:00:00|2001-10-01 00:00:00|2|300|300|300|300|0|0|0|25200000|0|84000|84000 +a_3@PERMANENT|2001-07-01 00:00:00|2001-10-01 00:00:00|3|300|300|300|300|0|0|0|109800000|0|366000|366000 +a_4@PERMANENT|2001-10-01 00:00:00|2002-01-01 00:00:00|1|400|400|400|400|0|0|0|12000000|0|30000|30000 +a_4@PERMANENT|2001-10-01 00:00:00|2002-01-01 00:00:00|2|400|400|400|400|0|0|0|33600000|0|84000|84000 +a_4@PERMANENT|2001-10-01 00:00:00|2002-01-01 00:00:00|3|400|400|400|400|0|0|0|146400000|0|366000|366000 +""" + + for ref, res in zip( + univar_text.split("\n"), t_rast_univar_zones.outputs.stdout.split("\n") + ): + if ref and res: + ref_line = ref.split("|", 1)[1] + res_line = res.split("|", 1)[1] + self.assertLooksLike(ref_line, res_line) + if __name__ == "__main__": from grass.gunittest.main import test From 86d0e7905e76fc956a6d90880514b54fb3e6bc6d Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Mon, 24 Oct 2022 21:11:52 +0200 Subject: [PATCH 051/123] wxGUI/modules: fix import PostGIS geometry data (#2490) --- gui/wxpython/core/utils.py | 1 + gui/wxpython/gui_core/gselect.py | 17 +++++++++++++++-- gui/wxpython/modules/import_export.py | 8 +++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/gui/wxpython/core/utils.py b/gui/wxpython/core/utils.py index ec0520c7ae6..079da69506e 100644 --- a/gui/wxpython/core/utils.py +++ b/gui/wxpython/core/utils.py @@ -668,6 +668,7 @@ def _parseFormats(output, writableOnly=False): continue if name in ( "PostgreSQL", + "PostgreSQL/PostGIS", "SQLite", "SQLite / Spatialite", "ODBC", diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index 68b670d3c1f..b60a12416b0 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -2003,8 +2003,11 @@ def SetSourceType(self, sourceType): if sourceType == "db": self.dbWidgets["format"].SetItems(list(self.dbFormats.values())) if self.dbFormats: - if "PostgreSQL" in self.dbFormats.values(): + db_formats = self.dbFormats.values() + if "PostgreSQL" in db_formats: self.dbWidgets["format"].SetStringSelection("PostgreSQL") + elif "PostgreSQL/PostGIS" in db_formats: + self.dbWidgets["format"].SetStringSelection("PostgreSQL/PostGIS") else: self.dbWidgets["format"].SetSelection(0) self.dbWidgets["format"].Enable() @@ -2102,6 +2105,7 @@ def GetDsn(self): if self._sourceType == "db": if self.dbWidgets["format"].GetStringSelection() in ( "PostgreSQL", + "PostgreSQL/PostGIS", "PostGIS Raster driver", ): ret = RunCommand("db.login", read=True, quiet=True, flags="p") @@ -2171,10 +2175,19 @@ def SetDatabase(self, db): showDirbrowse = db in ("FileGDB") showChoice = db in ( "PostgreSQL", + "PostgreSQL/PostGIS", "PostGIS WKT Raster driver", "PostGIS Raster driver", ) - enableFeatType = self.dest and self.ogr and db in ("PostgreSQL") + enableFeatType = ( + self.dest + and self.ogr + and db + in ( + "PostgreSQL", + "PostgreSQL/PostGIS", + ) + ) showText = not (showBrowse or showChoice or showDirbrowse) sizer.Show(self.dbWidgets["browse"], show=showBrowse) diff --git a/gui/wxpython/modules/import_export.py b/gui/wxpython/modules/import_export.py index 389ed98b8ac..02034d9fb12 100644 --- a/gui/wxpython/modules/import_export.py +++ b/gui/wxpython/modules/import_export.py @@ -613,13 +613,19 @@ def OnRun(self, event): return dsn = self.dsnInput.GetDsn() + if not dsn: + return ext = self.dsnInput.GetFormatExt() # determine data driver for PostGIS links self.popOGR = False if ( self.dsnInput.GetType() == "db" - and self.dsnInput.GetFormat() == "PostgreSQL" + and self.dsnInput.GetFormat() + in ( + "PostgreSQL", + "PostgreSQL/PostGIS", + ) and "GRASS_VECTOR_OGR" not in os.environ ): self.popOGR = True From 206ac04bf0ce2eacbead5beec6e152127c15a2c3 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Tue, 25 Oct 2022 19:32:46 +0200 Subject: [PATCH 052/123] wxGUI/psmap: don't set StatusBar widget text when frame is closed (#2487) --- gui/wxpython/psmap/frame.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gui/wxpython/psmap/frame.py b/gui/wxpython/psmap/frame.py index e0a5d20a0fa..b31b154d924 100644 --- a/gui/wxpython/psmap/frame.py +++ b/gui/wxpython/psmap/frame.py @@ -513,7 +513,10 @@ def OnCmdDone(self, event): if event.userData["temp"]: grass.try_remove(event.userData["filename"]) - self.delayedCall = wx.CallLater(4000, lambda: self.SetStatusText("", 0)) + self.delayedCall = wx.CallLater( + 4000, + lambda: self.SetStatusText("", 0) if self else None, + ) def getFile(self, wildcard): suffix = [] From bece7f7b88a5a429e0b560b89c919a57af7477e7 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Tue, 25 Oct 2022 23:05:51 -0400 Subject: [PATCH 053/123] wxGUI: remove custom v.clean interface to simplify maintenance (#2553) --- gui/wxpython/lmgr/frame.py | 8 - gui/wxpython/main_window/frame.py | 8 - gui/wxpython/modules/__init__.py | 1 - gui/wxpython/modules/vclean.py | 617 ------------------------------ gui/wxpython/xml/toolboxes.xml | 4 +- gui/wxpython/xml/wxgui_items.xml | 7 - 6 files changed, 3 insertions(+), 642 deletions(-) delete mode 100644 gui/wxpython/modules/vclean.py diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index b26d7b476f2..6196e466f1f 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -1738,14 +1738,6 @@ def OnMapCalculator(self, event, cmd=""): win.CentreOnScreen() win.Show() - def OnVectorCleaning(self, event, cmd=""): - """Init interactive vector cleaning""" - from modules.vclean import VectorCleaningFrame - - win = VectorCleaningFrame(parent=self) - win.CentreOnScreen() - win.Show() - def OnRasterOutputFormat(self, event): """Set raster output format handler""" self.OnMenuCmd(cmd=["r.external.out"]) diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index 32abfc032c5..e09622957ef 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -1825,14 +1825,6 @@ def OnMapCalculator(self, event, cmd=""): win.CentreOnScreen() win.Show() - def OnVectorCleaning(self, event, cmd=""): - """Init interactive vector cleaning""" - from modules.vclean import VectorCleaningFrame - - win = VectorCleaningFrame(parent=self) - win.CentreOnScreen() - win.Show() - def OnRasterOutputFormat(self, event): """Set raster output format handler""" self.OnMenuCmd(cmd=["r.external.out"]) diff --git a/gui/wxpython/modules/__init__.py b/gui/wxpython/modules/__init__.py index e33dbd03070..93c2970fdef 100644 --- a/gui/wxpython/modules/__init__.py +++ b/gui/wxpython/modules/__init__.py @@ -1,7 +1,6 @@ all = [ "mcalc_builder", "extensions", - "vclean", "colorrules", "histogram", ] diff --git a/gui/wxpython/modules/vclean.py b/gui/wxpython/modules/vclean.py deleted file mode 100644 index f678507a231..00000000000 --- a/gui/wxpython/modules/vclean.py +++ /dev/null @@ -1,617 +0,0 @@ -""" -@package modules.vclean - -@brief Dialog for interactive construction of vector cleaning -operations - -Classes: - - vclean::VectorCleaningFrame - -(C) 2010-2011 by the GRASS Development Team -This program is free software under the GNU General Public License -(>=v2). Read the file COPYING that comes with GRASS for details. - -@author Markus Metz -""" - -import os - -import wx -import wx.lib.scrolledpanel as scrolled - -from core.gcmd import RunCommand, GError -from core import globalvar -from gui_core.gselect import Select -from core.settings import UserSettings -from grass.script import core as grass -from gui_core.wrap import Button, StaticText, StaticBox, TextCtrl - - -class VectorCleaningFrame(wx.Frame): - def __init__( - self, - parent, - id=wx.ID_ANY, - title=_("Set up vector cleaning tools"), - style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER, - **kwargs, - ): - """ - Dialog for interactively defining vector cleaning tools - """ - wx.Frame.__init__(self, parent, id, title, style=style, **kwargs) - - self.parent = parent # GMFrame - if self.parent: - self.log = self.parent.GetLogWindow() - else: - self.log = None - - # grass command - self.cmd = "v.clean" - - # statusbar - self.CreateStatusBar() - - # icon - self.SetIcon( - wx.Icon(os.path.join(globalvar.ICONDIR, "grass.ico"), wx.BITMAP_TYPE_ICO) - ) - - self.panel = wx.Panel(parent=self, id=wx.ID_ANY) - - # input map to clean - self.inmap = "" - - # cleaned output map - self.outmap = "" - - self.ftype = "" - - # cleaning tools - self.toolslines = {} - - self.tool_desc_list = [ - _("break lines/boundaries"), - _("remove duplicates"), - _("remove dangles"), - _("change boundary dangles to lines"), - _("remove bridges"), - _("change bridges to lines"), - _("snap lines/boundaries"), - _("remove duplicate area centroids"), - _("break polygons"), - _("prune lines/boundaries"), - _("remove small areas"), - _("remove lines/boundaries of zero length"), - _("remove small angles at nodes"), - ] - - self.tool_list = [ - "break", - "rmdupl", - "rmdangle", - "chdangle", - "rmbridge", - "chbridge", - "snap", - "rmdac", - "bpol", - "prune", - "rmarea", - "rmline", - "rmsa", - ] - - self.ftype = ["point", "line", "boundary", "centroid", "area", "face"] - - self.n_ftypes = len(self.ftype) - - self.tools_string = "" - self.thresh_string = "" - self.ftype_string = "" - - self.SetStatusText(_("Set up vector cleaning tools")) - self.elem = "vector" - self.ctlabel = _("Choose cleaning tools and set thresholds") - - # top controls - self.inmaplabel = StaticText( - parent=self.panel, id=wx.ID_ANY, label=_("Select input vector map:") - ) - self.selectionInput = Select( - parent=self.panel, - id=wx.ID_ANY, - size=globalvar.DIALOG_GSELECT_SIZE, - type="vector", - ) - self.ftype_check = {} - ftypeBox = StaticBox( - parent=self.panel, id=wx.ID_ANY, label=_(" Feature type: ") - ) - self.ftypeSizer = wx.StaticBoxSizer(ftypeBox, wx.HORIZONTAL) - - self.outmaplabel = StaticText( - parent=self.panel, id=wx.ID_ANY, label=_("Select output vector map:") - ) - self.selectionOutput = Select( - parent=self.panel, - id=wx.ID_ANY, - size=globalvar.DIALOG_GSELECT_SIZE, - mapsets=[ - grass.gisenv()["MAPSET"], - ], - fullyQualified=False, - type="vector", - ) - - self.overwrite = wx.CheckBox( - parent=self.panel, - id=wx.ID_ANY, - label=_("Allow output files to overwrite existing files"), - ) - self.overwrite.SetValue( - UserSettings.Get(group="cmd", key="overwrite", subkey="enabled") - ) - - # cleaning tools - self.ct_label = StaticText(parent=self.panel, id=wx.ID_ANY, label=self.ctlabel) - - self.ct_panel = self._toolsPanel() - - # buttons to manage cleaning tools - self.btn_add = Button(parent=self.panel, id=wx.ID_ADD) - self.btn_remove = Button(parent=self.panel, id=wx.ID_REMOVE) - self.btn_moveup = Button(parent=self.panel, id=wx.ID_UP) - self.btn_movedown = Button(parent=self.panel, id=wx.ID_DOWN) - - # add one tool as default - self.AddTool() - self.selected = -1 - - # Buttons - self.btn_close = Button(parent=self.panel, id=wx.ID_CLOSE) - self.btn_run = Button(parent=self.panel, id=wx.ID_ANY, label=_("&Run")) - self.btn_run.SetDefault() - self.btn_clipboard = Button(parent=self.panel, id=wx.ID_COPY) - self.btn_clipboard.SetToolTip( - _("Copy the current command string to the clipboard (Ctrl+C)") - ) - self.btn_help = Button(parent=self.panel, id=wx.ID_HELP) - - # bindings - self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose) - self.btn_run.Bind(wx.EVT_BUTTON, self.OnCleaningRun) - self.btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy) - self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp) - - self.btn_add.Bind(wx.EVT_BUTTON, self.OnAddTool) - self.btn_remove.Bind(wx.EVT_BUTTON, self.OnClearTool) - self.btn_moveup.Bind(wx.EVT_BUTTON, self.OnMoveToolUp) - self.btn_movedown.Bind(wx.EVT_BUTTON, self.OnMoveToolDown) - - # layout - self._layout() - - self.SetMinSize(self.GetBestSize()) - - self.CentreOnScreen() - - def _layout(self): - sizer = wx.BoxSizer(wx.VERTICAL) - - # - # input output - # - inSizer = wx.GridBagSizer(hgap=5, vgap=5) - - inSizer.Add( - self.inmaplabel, - pos=(0, 0), - flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, - border=1, - ) - inSizer.Add( - self.selectionInput, - pos=(1, 0), - flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, - border=1, - ) - - self.ftype_check = [ - wx.CheckBox(parent=self.panel, id=wx.ID_ANY, label=_("point")), - wx.CheckBox(parent=self.panel, id=wx.ID_ANY, label=_("line")), - wx.CheckBox(parent=self.panel, id=wx.ID_ANY, label=_("boundary")), - wx.CheckBox(parent=self.panel, id=wx.ID_ANY, label=_("centroid")), - wx.CheckBox(parent=self.panel, id=wx.ID_ANY, label=_("area")), - wx.CheckBox(parent=self.panel, id=wx.ID_ANY, label=_("face")), - ] - - typeoptSizer = wx.BoxSizer(wx.HORIZONTAL) - for num in range(0, self.n_ftypes): - type_box = self.ftype_check[num] - if self.ftype[num] in ("point", "line", "area"): - type_box.SetValue(True) - typeoptSizer.Add(type_box, flag=wx.ALIGN_LEFT, border=1) - - self.ftypeSizer.Add( - typeoptSizer, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=2 - ) - - outSizer = wx.GridBagSizer(hgap=5, vgap=5) - - outSizer.Add( - self.outmaplabel, - pos=(0, 0), - flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, - border=1, - ) - outSizer.Add( - self.selectionOutput, - pos=(1, 0), - flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, - border=1, - ) - replaceSizer = wx.BoxSizer(wx.HORIZONTAL) - replaceSizer.Add( - self.overwrite, proportion=1, flag=wx.ALL | wx.EXPAND, border=1 - ) - - outSizer.Add(replaceSizer, pos=(2, 0), flag=wx.ALL | wx.EXPAND, border=1) - - # - # tools selection - # - bodySizer = wx.GridBagSizer(hgap=5, vgap=5) - - bodySizer.Add(self.ct_label, pos=(0, 0), span=(1, 2), flag=wx.ALL, border=5) - - bodySizer.Add(self.ct_panel, pos=(1, 0), span=(1, 2)) - - manageBoxSizer = wx.GridBagSizer(hgap=10, vgap=1) - # start with row 1 for nicer layout - manageBoxSizer.Add(self.btn_add, pos=(1, 0), border=2, flag=wx.ALL | wx.EXPAND) - manageBoxSizer.Add( - self.btn_remove, pos=(2, 0), border=2, flag=wx.ALL | wx.EXPAND - ) - manageBoxSizer.Add( - self.btn_moveup, pos=(3, 0), border=2, flag=wx.ALL | wx.EXPAND - ) - manageBoxSizer.Add( - self.btn_movedown, pos=(4, 0), border=2, flag=wx.ALL | wx.EXPAND - ) - - bodySizer.Add( - manageBoxSizer, pos=(1, 2), flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5 - ) - - bodySizer.AddGrowableCol(2) - - # - # standard buttons - # - btnSizer = wx.BoxSizer(wx.HORIZONTAL) - btnSizer.Add(self.btn_close, flag=wx.LEFT | wx.RIGHT, border=5) - btnSizer.Add(self.btn_run, flag=wx.LEFT | wx.RIGHT, border=5) - btnSizer.Add(self.btn_clipboard, flag=wx.LEFT | wx.RIGHT, border=5) - btnSizer.Add(self.btn_help, flag=wx.LEFT | wx.RIGHT, border=5) - - # - # put it all together - # - sizer.Add(inSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5) - - sizer.Add(self.ftypeSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5) - - sizer.Add(outSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5) - - sizer.Add( - wx.StaticLine(parent=self, id=wx.ID_ANY, style=wx.LI_HORIZONTAL), - proportion=0, - flag=wx.EXPAND | wx.ALL, - border=5, - ) - - sizer.Add(bodySizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) - - sizer.Add( - wx.StaticLine(parent=self, id=wx.ID_ANY, style=wx.LI_HORIZONTAL), - proportion=0, - flag=wx.EXPAND | wx.ALL, - border=5, - ) - - sizer.Add(btnSizer, proportion=0, flag=wx.ALL | wx.ALIGN_RIGHT, border=5) - - self.panel.SetAutoLayout(True) - self.panel.SetSizer(sizer) - sizer.Fit(self.panel) - - self.Layout() - - def _toolsPanel(self): - ct_panel = scrolled.ScrolledPanel( - parent=self.panel, id=wx.ID_ANY, size=(500, 240), style=wx.SUNKEN_BORDER - ) - - self.ct_sizer = wx.GridBagSizer(vgap=2, hgap=4) - - ct_panel.SetSizer(self.ct_sizer) - ct_panel.SetAutoLayout(True) - - return ct_panel - - def OnAddTool(self, event): - """Add tool button pressed""" - self.AddTool() - - def AddTool(self): - snum = len(self.toolslines.keys()) - num = snum + 1 - # tool - tool_cbox = wx.ComboBox( - parent=self.ct_panel, - id=1000 + num, - size=(300, -1), - choices=self.tool_desc_list, - style=wx.CB_DROPDOWN | wx.CB_READONLY | wx.TE_PROCESS_ENTER, - ) - self.Bind(wx.EVT_COMBOBOX, self.OnSetTool, tool_cbox) - # threshold - txt_ctrl = TextCtrl( - parent=self.ct_panel, - id=2000 + num, - value="0.00", - size=(100, -1), - style=wx.TE_NOHIDESEL, - ) - self.Bind(wx.EVT_TEXT, self.OnThreshValue, txt_ctrl) - - # select with tool number - select = wx.CheckBox(parent=self.ct_panel, id=num, label=str(num) + ".") - select.SetValue(False) - self.Bind(wx.EVT_CHECKBOX, self.OnSelect, select) - - # start with row 1 and col 1 for nicer layout - self.ct_sizer.Add(select, pos=(num, 1), flag=wx.ALIGN_CENTER | wx.RIGHT) - self.ct_sizer.Add( - tool_cbox, pos=(num, 2), flag=wx.ALIGN_CENTER | wx.RIGHT, border=5 - ) - self.ct_sizer.Add( - txt_ctrl, pos=(num, 3), flag=wx.ALIGN_CENTER | wx.RIGHT, border=5 - ) - - self.toolslines[num] = {"tool_desc": "", "tool": "", "thresh": "0.00"} - - self.ct_panel.Layout() - self.ct_panel.SetupScrolling() - - def OnClearTool(self, event): - """Remove tool button pressed""" - id = self.selected - - if id > 0: - self.FindWindowById(id + 1000).SetValue("") - self.toolslines[id]["tool_desc"] = "" - self.toolslines[id]["tool"] = "" - self.SetStatusText(_("%s. cleaning tool removed, will be ignored") % id) - else: - self.SetStatusText(_("Please select a cleaning tool to remove")) - - def OnMoveToolUp(self, event): - """Move up tool button pressed""" - id = self.selected - - if id > 1: - id_up = id - 1 - this_toolline = self.toolslines[id] - up_toolline = self.toolslines[id_up] - - self.FindWindowById(id_up).SetValue(True) - self.FindWindowById(id_up + 1000).SetValue(this_toolline["tool_desc"]) - self.FindWindowById(id_up + 2000).SetValue(this_toolline["thresh"]) - self.toolslines[id_up] = this_toolline - - self.FindWindowById(id).SetValue(False) - self.FindWindowById(id + 1000).SetValue(up_toolline["tool_desc"]) - self.FindWindowById(id + 2000).SetValue(up_toolline["thresh"]) - self.toolslines[id] = up_toolline - self.selected = id_up - self.SetStatusText(_("%s. cleaning tool moved up") % id) - elif id == 1: - self.SetStatusText(_("1. cleaning tool can not be moved up ")) - elif id == -1: - self.SetStatusText(_("Please select a cleaning tool to move up")) - - def OnMoveToolDown(self, event): - """Move down tool button pressed""" - id = self.selected - snum = len(self.toolslines.keys()) - - if id > 0 and id < snum: - id_down = id + 1 - this_toolline = self.toolslines[id] - down_toolline = self.toolslines[id_down] - - self.FindWindowById(id_down).SetValue(True) - self.FindWindowById(id_down + 1000).SetValue(this_toolline["tool_desc"]) - self.FindWindowById(id_down + 2000).SetValue(this_toolline["thresh"]) - self.toolslines[id_down] = this_toolline - - self.FindWindowById(id).SetValue(False) - self.FindWindowById(id + 1000).SetValue(down_toolline["tool_desc"]) - self.FindWindowById(id + 2000).SetValue(down_toolline["thresh"]) - self.toolslines[id] = down_toolline - self.selected = id_down - self.SetStatusText(_("%s. cleaning tool moved down") % id) - elif id == snum: - self.SetStatusText(_("Last cleaning tool can not be moved down ")) - elif id == -1: - self.SetStatusText(_("Please select a cleaning tool to move down")) - - def OnSetTool(self, event): - """Tool was defined""" - id = event.GetId() - tool_no = id - 1000 - num = self.FindWindowById(id).GetCurrentSelection() - - self.toolslines[tool_no]["tool_desc"] = self.tool_desc_list[num] - self.toolslines[tool_no]["tool"] = self.tool_list[num] - - self.SetStatusText( - str(tool_no) + ". " + _("cleaning tool: '%s'") % (self.tool_list[num]) - ) - - def OnThreshValue(self, event): - """Threshold value was entered""" - id = event.GetId() - num = id - 2000 - self.toolslines[num]["thresh"] = self.FindWindowById(id).GetValue() - - self.SetStatusText( - _("Threshold for %(num)s. tool '%(tool)s': %(thresh)s") - % { - "num": num, - "tool": self.toolslines[num]["tool"], - "thresh": self.toolslines[num]["thresh"], - } - ) - - def OnSelect(self, event): - """Tool was selected""" - id = event.GetId() - - if self.selected > -1 and self.selected != id: - win = self.FindWindowById(self.selected) - win.SetValue(False) - - if self.selected != id: - self.selected = id - else: - self.selected = -1 - - def OnDone(self, event): - """Command done""" - self.SetStatusText("") - - def OnCleaningRun(self, event): - """Builds options and runs v.clean""" - self.GetCmdStrings() - - err = list() - for p, name in ( - (self.inmap, _("Name of input vector map")), - (self.outmap, _("Name for output vector map")), - (self.tools_string, _("Tools")), - (self.thresh_string, _("Threshold")), - ): - if not p: - err.append(_("'%s' not defined") % name) - if err: - GError( - _("Some parameters not defined. Operation " "canceled.\n\n%s") - % "\n".join(err), - parent=self, - ) - return - - self.SetStatusText(_("Executing selected cleaning operations...")) - snum = len(self.toolslines.keys()) - - if self.log: - cmd = [ - self.cmd, - "input=%s" % self.inmap, - "output=%s" % self.outmap, - "tool=%s" % self.tools_string, - "thres=%s" % self.thresh_string, - ] - if self.ftype_string: - cmd.append("type=%s" % self.ftype_string) - if self.overwrite.IsChecked(): - cmd.append("--overwrite") - - self.log.RunCmd(cmd, onDone=self.OnDone) - self.parent.Raise() - else: - if self.overwrite.IsChecked(): - overwrite = True - else: - overwrite = False - - RunCommand( - self.cmd, - input=self.inmap, - output=self.outmap, - type=self.ftype_string, - tool=self.tools_string, - thresh=self.thresh_string, - overwrite=overwrite, - ) - - def OnClose(self, event): - self.Destroy() - - def OnHelp(self, event): - """Show GRASS manual page""" - RunCommand("g.manual", quiet=True, parent=self, entry=self.cmd) - - def OnCopy(self, event): - """Copy the command""" - cmddata = wx.TextDataObject() - # get tool and thresh strings - self.GetCmdStrings() - cmdstring = "%s" % (self.cmd) - # list -> string - cmdstring += " input=%s output=%s type=%s tool=%s thres=%s" % ( - self.inmap, - self.outmap, - self.ftype_string, - self.tools_string, - self.thresh_string, - ) - if self.overwrite.IsChecked(): - cmdstring += " --overwrite" - - cmddata.SetText(cmdstring) - if wx.TheClipboard.Open(): - wx.TheClipboard.SetData(cmddata) - wx.TheClipboard.Close() - self.SetStatusText(_("Vector cleaning command copied to clipboard")) - - def GetCmdStrings(self): - self.tools_string = "" - self.thresh_string = "" - self.ftype_string = "" - # feature types - first = 1 - for num in range(0, self.n_ftypes - 1): - if self.ftype_check[num].IsChecked(): - if first: - self.ftype_string = "%s" % self.ftype[num] - first = 0 - else: - self.ftype_string += ",%s" % self.ftype[num] - - # cleaning tools - first = 1 - snum = len(self.toolslines.keys()) - for num in range(1, snum + 1): - if self.toolslines[num]["tool"]: - if first: - self.tools_string = "%s" % self.toolslines[num]["tool"] - self.thresh_string = "%s" % self.toolslines[num]["thresh"] - first = 0 - else: - self.tools_string += ",%s" % self.toolslines[num]["tool"] - self.thresh_string += ",%s" % self.toolslines[num]["thresh"] - - self.inmap = self.selectionInput.GetValue() - self.outmap = self.selectionOutput.GetValue() - - -if __name__ == "__main__": - app = wx.App() - frame = VectorCleaningFrame(parent=None) - frame.Show() - app.MainLoop() diff --git a/gui/wxpython/xml/toolboxes.xml b/gui/wxpython/xml/toolboxes.xml index 9f4d8d74880..fb21827b5a0 100644 --- a/gui/wxpython/xml/toolboxes.xml +++ b/gui/wxpython/xml/toolboxes.xml @@ -1205,7 +1205,9 @@ - + + + diff --git a/gui/wxpython/xml/wxgui_items.xml b/gui/wxpython/xml/wxgui_items.xml index ea8cca9f502..a07e357090f 100644 --- a/gui/wxpython/xml/wxgui_items.xml +++ b/gui/wxpython/xml/wxgui_items.xml @@ -344,13 +344,6 @@ OnNewVector Create new empty vector map - - - OnVectorCleaning - v.clean - Toolset for cleaning topology of vector map. - vector,topology,geometry - OnVectorRules From 569be6c5f18f75a0733443a4714c796db58f5af0 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Wed, 26 Oct 2022 05:27:13 +0200 Subject: [PATCH 054/123] python/grass/pygrass: reset back MAPSET search path after GridModule class instance finish (#2567) * Fix copy_mapset() func doc test --- python/grass/pygrass/modules/grid/grid.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/python/grass/pygrass/modules/grid/grid.py b/python/grass/pygrass/modules/grid/grid.py index fe9cb2140b2..d03edc874f3 100644 --- a/python/grass/pygrass/modules/grid/grid.py +++ b/python/grass/pygrass/modules/grid/grid.py @@ -93,10 +93,9 @@ def copy_mapset(mapset, path): >>> sorted(os.listdir(os.path.join(path, 'PERMANENT'))) ['DEFAULT_WIND', 'PROJ_INFO', 'PROJ_UNITS', 'VAR', 'WIND'] >>> sorted(os.listdir(os.path.join(path, mname))) # doctest: +ELLIPSIS - [...'SEARCH_PATH',...'WIND'] + [...'WIND'...] >>> import shutil >>> shutil.rmtree(path) - """ per_old = os.path.join(mapset.gisdbase, mapset.location, "PERMANENT") per_new = os.path.join(path, "PERMANENT") @@ -705,9 +704,6 @@ def run(self, patch=True, clean=True): def patch(self): """Patch the final results.""" bboxes = split_region_tiles(width=self.width, height=self.height) - loc = Location() - mset = loc[self.mset.name] - mset.visible.extend(loc.mapsets()) noutputs = 0 for otmap in self.module.outputs: otm = self.module.outputs[otmap] From 04154b4629c85881630c51743a8ed09f1e79f4f1 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Thu, 27 Oct 2022 05:39:50 +0200 Subject: [PATCH 055/123] wxGUI/gui_core: fix Create or edit image group dialog Select all CheckBox widget for selecting all items (#2514) --- gui/wxpython/gui_core/dialogs.py | 3 +-- gui/wxpython/gui_core/wrap.py | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gui/wxpython/gui_core/dialogs.py b/gui/wxpython/gui_core/dialogs.py index b625d340a7a..7b682c0d084 100644 --- a/gui/wxpython/gui_core/dialogs.py +++ b/gui/wxpython/gui_core/dialogs.py @@ -986,8 +986,7 @@ def OnGSelAll(self, event): if not check: self.gLayerBox.DeselectAll() else: - for item in range(self.subgListBox.GetCount()): - self.gLayerBox.Select(item) + self.gLayerBox.SelectAll() event.Skip() diff --git a/gui/wxpython/gui_core/wrap.py b/gui/wxpython/gui_core/wrap.py index 674b87fac48..325be0cf2bf 100644 --- a/gui/wxpython/gui_core/wrap.py +++ b/gui/wxpython/gui_core/wrap.py @@ -913,6 +913,10 @@ def DeselectAll(self): for i in range(self.GetCount()): self.Deselect(i) + def SelectAll(self): + for i in range(self.GetCount()): + self.Select(i) + class HyperlinkCtrl(HyperlinkCtrl_): """Wrapper around HyperlinkCtrl to have more control From 8af0fa41b77b0df16a8d0c4bc59f23c6970a9406 Mon Sep 17 00:00:00 2001 From: Linda Kladivova <49241681+lindakladivova@users.noreply.github.com> Date: Fri, 28 Oct 2022 06:10:14 +0200 Subject: [PATCH 056/123] wxGUI: Fix behaviour of top Single-Window GUI toolbars (#2568) Use agw.aui toolbar as the main toolbar to avoid strange behavior. This requires restructuring Toolbar classes. Co-authored-by: Anna Petrasova --- gui/wxpython/gui_core/toolbars.py | 238 ++++++++++++++++++++++-------- gui/wxpython/iscatt/toolbars.py | 8 +- gui/wxpython/lmgr/toolbars.py | 18 +-- gui/wxpython/mapdisp/toolbars.py | 4 +- gui/wxpython/psmap/toolbars.py | 2 +- 5 files changed, 193 insertions(+), 77 deletions(-) diff --git a/gui/wxpython/gui_core/toolbars.py b/gui/wxpython/gui_core/toolbars.py index 87835b3e9b6..8800e4c7bd6 100644 --- a/gui/wxpython/gui_core/toolbars.py +++ b/gui/wxpython/gui_core/toolbars.py @@ -20,6 +20,7 @@ import os import wx +import wx.lib.agw.aui as aui from core import globalvar from core.debug import Debug @@ -85,52 +86,27 @@ } -class BaseToolbar(ToolBar): - """Abstract toolbar class. - - Following code shows how to create new basic toolbar: - - - class MyToolbar(BaseToolbar): - def __init__(self, parent): - BaseToolbar.__init__(self, parent) - self.InitToolbar(self._toolbarData()) - self.Realize() - - def _toolbarData(self): - # e.g. ("help", _("Help")) tool short label (triangle/arrow - # at the right side of the toolbar) - return self._getToolbarData( - ( - ("help", Icons["help"].label), - Icons["help"], - self.parent.OnHelp - ), - ) - """ +class ToolbarController: + """Controller specialized for wx.ToolBar subclass.""" - def __init__( - self, parent, toolSwitcher=None, style=wx.NO_BORDER | wx.TB_HORIZONTAL - ): + def __init__(self, classObject, widget, parent, toolSwitcher): + """ + :param classObject: toolbar class name (object, i.e. wx.Toolbar) + :param widget: toolbar instance + """ + self.classObject = classObject + self.widget = widget self.parent = parent - wx.ToolBar.__init__(self, parent=self.parent, id=wx.ID_ANY, style=style) - - self._default = None - self.SetToolBitmapSize(globalvar.toolbarSize) - self.toolSwitcher = toolSwitcher self.handlers = {} + self.data = None def InitToolbar(self, toolData): """Initialize toolbar, add tools to the toolbar""" for tool in toolData: self.CreateTool(*tool) - self._data = toolData - - def _toolbarData(self): - """Toolbar data (virtual)""" - return None + self.data = toolData def CreateTool(self, label, bitmap, kind, shortHelp, longHelp, handler, pos=-1): """Add tool to the toolbar @@ -147,32 +123,47 @@ def CreateTool(self, label, bitmap, kind, shortHelp, longHelp, handler, pos=-1): internal_label = label if label: - tool = vars(self)[internal_label] = NewId() + tool = vars(self.widget)[internal_label] = NewId() Debug.msg( 3, "CreateTool(): tool=%d, label=%s bitmap=%s" % (tool, label, bitmap) ) if pos < 0: - toolWin = self.AddLabelTool( - tool, label, bitmap, bmpDisabled, kind, shortHelp, longHelp + toolWin = self.classObject.AddTool( + self.widget, + tool, + label, + bitmap, + bmpDisabled, + kind, + shortHelp, + longHelp, ) else: - toolWin = self.InsertLabelTool( - pos, tool, label, bitmap, bmpDisabled, kind, shortHelp, longHelp + toolWin = self.classObject.InsertTool( + self.widget, + pos, + tool, + label, + bitmap, + bmpDisabled, + kind, + shortHelp, + longHelp, ) self.handlers[tool] = handler - self.Bind(wx.EVT_TOOL, handler, toolWin) - self.Bind(wx.EVT_TOOL, self.OnTool, toolWin) + self.widget.Bind(wx.EVT_TOOL, handler, toolWin) + self.widget.Bind(wx.EVT_TOOL, self.OnTool, toolWin) else: # separator - self.AddSeparator() + self.classObject.AddSeparator(self.widget) return tool - def EnableLongHelp(self, enable=True): + def EnableLongHelp(self, enable): """Enable/disable long help :param enable: True for enable otherwise disable """ - for tool in self._data: + for tool in self.data: if isinstance(tool[0], tuple): if tool[0][0] == "": # separator continue @@ -183,10 +174,12 @@ def EnableLongHelp(self, enable=True): continue else: internal_label = tool[0] + + label = vars(self.widget)[internal_label] if enable: - self.SetToolLongHelp(vars(self)[internal_label], tool[4]) + self.classObject.SetToolLongHelp(self.widget, label, tool[4]) else: - self.SetToolLongHelp(vars(self)[internal_label], "") + self.classObject.SetToolLongHelp(self.widget, label, "") def OnTool(self, event): """Tool selected""" @@ -196,14 +189,14 @@ def OnTool(self, event): event.Skip() def SelectTool(self, id): - self.ToggleTool(id, True) + self.classObject.ToggleTool(self.widget, id, True) self.toolSwitcher.ToolChanged(id) self.handlers[id](event=None) def SelectDefault(self): """Select default tool""" - self.SelectTool(self._default) + self.SelectTool(self.widget._default) def FixSize(self, width): """Fix toolbar width on Windows @@ -212,8 +205,8 @@ def FixSize(self, width): Determine why combobox causes problems here """ if platform.system() == "Windows": - size = self.GetBestSize() - self.SetSize((size[0] + width, size[1])) + size = self.classObject.GetBestSize(self.widget) + self.classObject.SetSize(self.widget, (size[0] + width, size[1])) def Enable(self, tool, enable=True): """Enable/Disable defined tool @@ -223,23 +216,23 @@ def Enable(self, tool, enable=True): """ try: if isinstance(tool, tuple): - id = getattr(self, tool[0]) + id = getattr(self.widget, tool[0]) else: - id = getattr(self, tool) + id = getattr(self.widget, tool) except AttributeError: # TODO: test everything that this is not raised # this error was ignored for a long time raise AttributeError("Toolbar does not have a tool %s." % tool) return - self.EnableTool(id, enable) + self.classObject.EnableTool(self.widget, id, enable) def EnableAll(self, enable=True): """Enable/Disable all tools :param enable: True to enable otherwise disable tool """ - for item in self._toolbarData(): + for item in self.widget._toolbarData(): if not item[0]: continue self.Enable(item[0], enable) @@ -275,12 +268,12 @@ def _onMenu(self, data): item = wx.MenuItem(menu, wx.ID_ANY, icon.GetLabel()) item.SetBitmap(icon.GetBitmap(self.parent.iconsize)) menu.AppendItem(item) - self.Bind(wx.EVT_MENU, handler, item) + self.widget.Bind(wx.EVT_MENU, handler, item) - self.PopupMenu(menu) + self.classObject.PopupMenu(self.widget, menu) menu.Destroy() - def CreateSelectionButton(self, tooltip=_("Select graphics tool")): + def CreateSelectionButton(self, tooltip): """Add button to toolbar for selection of graphics drawing mode. Button must be custom (not toolbar tool) to set smaller width. @@ -293,9 +286,9 @@ def CreateSelectionButton(self, tooltip=_("Select graphics tool")): id=wx.ART_MISSING_IMAGE, client=wx.ART_TOOLBAR ) button = BitmapButton( - parent=self, + parent=self.widget, id=wx.ID_ANY, - size=((-1, self.GetToolSize()[1])), + size=((-1, self.classObject.GetToolSize(self.widget)[1])), bitmap=bitmap, style=wx.NO_BORDER, ) @@ -304,6 +297,129 @@ def CreateSelectionButton(self, tooltip=_("Select graphics tool")): return button +class AuiToolbarController(ToolbarController): + """Controller specialized for wx.lib.agw.aui.auibar.AuiToolBar subclass""" + + def _defineTool(self, name=None, icon=None, handler=None, item=wx.ITEM_NORMAL): + """Define tool. Position is not needed since wx.lib.agw.aui.auibar.AuiToolBar + does not have InsertTool method.""" + if name: + return ( + name, + icon.GetBitmap(), + item, + icon.GetLabel(), + icon.GetDesc(), + handler, + ) + return ("", "", "", "", "", "") # separator + + def CreateTool(self, label, bitmap, kind, shortHelp, longHelp, handler): + """Add tool to the toolbar""" + return super().CreateTool(label, bitmap, kind, shortHelp, longHelp, handler) + + +class BaseToolbar(ToolBar): + """Abstract basic toolbar class. + + Following code shows how to create new basic toolbar: + + + class MyToolbar(BaseToolbar): + def __init__(self, parent): + BaseToolbar.__init__(self, parent) + self.InitToolbar(self._toolbarData()) + self.Realize() + + def _toolbarData(self): + # e.g. ("help", _("Help")) tool short label (triangle/arrow + # at the right side of the toolbar) + return self._getToolbarData( + ( + ("help", Icons["help"].label), + Icons["help"], + self.parent.OnHelp + ), + ) + """ + + def __init__( + self, parent, toolSwitcher=None, style=wx.NO_BORDER | wx.TB_HORIZONTAL + ): + self.parent = parent + wx.ToolBar.__init__(self, parent=self.parent, id=wx.ID_ANY, style=style) + + self._default = None + self.SetToolBitmapSize(globalvar.toolbarSize) + + self.toolSwitcher = toolSwitcher + self.controller = ToolbarController( + classObject=ToolBar, + widget=self, + parent=self.parent, + toolSwitcher=toolSwitcher, + ) + + def _toolbarData(self): + """Toolbar data (virtual)""" + return None + + def Enable(self, tool, enable=True): + """@copydoc ToolbarController::Enable()""" + self.controller.Enable(tool, enable) + + def CreateTool(self, *args, **kwargs): + """@copydoc ToolbarController::CreateTool()""" + self.controller.CreateTool(*args, **kwargs) + + def __getattr__(self, name): + return getattr(self.controller, name) + + +class AuiToolbar(aui.AuiToolBar): + """Abstract AUI toolbar class. + + Toolbar for integration with the AUI layout system.""" + + def __init__( + self, + parent, + toolSwitcher=None, + style=wx.NO_BORDER | wx.TB_HORIZONTAL, + agwStyle=aui.AUI_TB_PLAIN_BACKGROUND, + ): + self.parent = parent + super().__init__( + parent=self.parent, id=wx.ID_ANY, style=style, agwStyle=agwStyle + ) + + self._default = None + self.SetToolBitmapSize(globalvar.toolbarSize) + + self.toolSwitcher = toolSwitcher + self.controller = AuiToolbarController( + classObject=aui.AuiToolBar, + widget=self, + parent=self.parent, + toolSwitcher=toolSwitcher, + ) + + def _toolbarData(self): + """Toolbar data (virtual)""" + return None + + def Enable(self, tool, enable=True): + """@copydoc ToolbarController::Enable()""" + self.controller.Enable(tool, enable) + + def CreateTool(self, *args, **kwargs): + """@copydoc ToolbarController::CreateTool()""" + self.controller.CreateTool(*args, **kwargs) + + def __getattr__(self, name): + return getattr(self.controller, name) + + class ToolSwitcher: """Class handling switching tools in toolbar and custom toggle buttons.""" diff --git a/gui/wxpython/iscatt/toolbars.py b/gui/wxpython/iscatt/toolbars.py index fd926ef9a0f..bab6cb584f6 100644 --- a/gui/wxpython/iscatt/toolbars.py +++ b/gui/wxpython/iscatt/toolbars.py @@ -133,7 +133,7 @@ def GetToolId(self, toolName): # TODO can be useful in base def SetPloltsMode(self, event, tool_name): self.scatt_mgr.modeSet.disconnect(self.ModeSet) if event.IsChecked(): - for i_tool_data in self._data: + for i_tool_data in self.controller.data: i_tool_name = i_tool_data[0] if not i_tool_name or i_tool_name in ["cats_mgr", "sel_pol_mode"]: continue @@ -159,7 +159,7 @@ def ModeSet(self, mode): self.UnsetMode() def UnsetMode(self): - for i_tool_data in self._data: + for i_tool_data in self.controller.data: i_tool_name = i_tool_data[0] if not i_tool_name or i_tool_name in ["cats_mgr", "sel_pol_mode"]: continue @@ -281,7 +281,7 @@ def _toolbarData(self): def SetMode(self, event, tool_name): self.scatt_mgr.modeSet.disconnect(self.ModeSet) if event.IsChecked(): - for i_tool_data in self._data: + for i_tool_data in self.controller.data: i_tool_name = i_tool_data[0] if not i_tool_name: continue @@ -300,7 +300,7 @@ def ModeSet(self, mode): self.UnsetMode() def UnsetMode(self): - for i_tool_data in self._data: + for i_tool_data in self.controller.data: i_tool_name = i_tool_data[0] if not i_tool_name: continue diff --git a/gui/wxpython/lmgr/toolbars.py b/gui/wxpython/lmgr/toolbars.py index e190f3a534d..cdcc1a6ac91 100644 --- a/gui/wxpython/lmgr/toolbars.py +++ b/gui/wxpython/lmgr/toolbars.py @@ -24,15 +24,15 @@ """ from core.gcmd import RunCommand -from gui_core.toolbars import BaseToolbar, BaseIcons +from gui_core.toolbars import BaseToolbar, AuiToolbar, BaseIcons from icons.icon import MetaIcon -class LMWorkspaceToolbar(BaseToolbar): +class LMWorkspaceToolbar(AuiToolbar): """Layer Manager `workspace` toolbar""" def __init__(self, parent): - BaseToolbar.__init__(self, parent) + AuiToolbar.__init__(self, parent) self.InitToolbar(self._toolbarData()) @@ -185,11 +185,11 @@ def _toolbarData(self): ) -class LMToolsToolbar(BaseToolbar): +class LMToolsToolbar(AuiToolbar): """Layer Manager `tools` toolbar""" def __init__(self, parent): - BaseToolbar.__init__(self, parent) + AuiToolbar.__init__(self, parent) self.InitToolbar(self._toolbarData()) @@ -259,11 +259,11 @@ def _toolbarData(self): ) -class LMMiscToolbar(BaseToolbar): +class LMMiscToolbar(AuiToolbar): """Layer Manager `misc` toolbar""" def __init__(self, parent): - BaseToolbar.__init__(self, parent) + AuiToolbar.__init__(self, parent) self.InitToolbar(self._toolbarData()) @@ -293,13 +293,13 @@ def _toolbarData(self): ) -class LMNvizToolbar(BaseToolbar): +class LMNvizToolbar(AuiToolbar): """Nviz toolbar""" def __init__(self, parent): self.lmgr = parent - BaseToolbar.__init__(self, parent) + AuiToolbar.__init__(self, parent) # only one dialog can be open self.settingsDialog = None diff --git a/gui/wxpython/mapdisp/toolbars.py b/gui/wxpython/mapdisp/toolbars.py index b8a5926e5f0..32de355e86b 100644 --- a/gui/wxpython/mapdisp/toolbars.py +++ b/gui/wxpython/mapdisp/toolbars.py @@ -280,12 +280,12 @@ def ChangeToolsDesc(self, mode2d): icons = BaseIcons else: icons = NvizIcons - for i, data in enumerate(self._data): + for i, data in enumerate(self.controller.data): for tool in ("zoomIn", "zoomOut"): if data[0] == tool: tmp = list(data) tmp[4] = icons[tool].GetDesc() - self._data[i] = tuple(tmp) + self.controller.data[i] = tuple(tmp) def OnSelectTool(self, event): """Select / enable tool available in tools list""" diff --git a/gui/wxpython/psmap/toolbars.py b/gui/wxpython/psmap/toolbars.py index 6c86f05c08a..4bea5184621 100644 --- a/gui/wxpython/psmap/toolbars.py +++ b/gui/wxpython/psmap/toolbars.py @@ -49,7 +49,7 @@ def __init__(self, parent, toolSwitcher): # custom button for graphics mode selection # TODO: could this be somehow generalized? - self.arrowButton = self.CreateSelectionButton() + self.arrowButton = self.CreateSelectionButton(tooltip=_("Select graphics tool")) self.arrowButtonId = self.InsertControl(18, self.arrowButton) self.arrowButton.Bind(wx.EVT_BUTTON, self.OnDrawGraphicsMenu) From 602b95981596f736ebc4a1f6ac06b77284f7c74c Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Fri, 28 Oct 2022 09:49:02 +0200 Subject: [PATCH 057/123] libgrass-interface: Upgrade to ctypesgen v1.1.1 (#2598) Notable changes are - Added support for sized integer types on Windows - Added support to handle function specifier keywords: inline and _Noreturn - Fixed mapping of 'short int' to c_short - Improved parsing of pragma directives --- python/libgrass_interface_generator/README.md | 5 +- .../ctypesgen/ctypedescs.py | 24 +- .../ctypesgen/parser/cgrammar.py | 33 +- .../ctypesgen/parser/ctypesparser.py | 2 + .../ctypesgen/parser/parsetab.py | 596 +++++++++--------- .../ctypesgen/parser/preprocessor.py | 5 - .../ctypesgen/version.py | 11 +- 7 files changed, 362 insertions(+), 314 deletions(-) diff --git a/python/libgrass_interface_generator/README.md b/python/libgrass_interface_generator/README.md index 857c436d237..e51a21dc796 100644 --- a/python/libgrass_interface_generator/README.md +++ b/python/libgrass_interface_generator/README.md @@ -1,9 +1,10 @@ -# librass interface generator +# libgrass interface generator ## Notes on ctypesgen Currently installed version: - (17 February 2022) +[**v1.1.1**](https://github.com/ctypesgen/ctypesgen/releases/tag/1.1.1) +(19 October 2022) ### How to update ctypesgen version diff --git a/python/libgrass_interface_generator/ctypesgen/ctypedescs.py b/python/libgrass_interface_generator/ctypesgen/ctypedescs.py index 901829f59fa..e787804619a 100755 --- a/python/libgrass_interface_generator/ctypesgen/ctypedescs.py +++ b/python/libgrass_interface_generator/ctypesgen/ctypedescs.py @@ -34,27 +34,41 @@ ("double", True, 0): "c_double", ("double", True, 1): "c_longdouble", ("int8_t", True, 0): "c_int8", + ("__int8_t", True, 0): "c_int8", ("__int8", True, 0): "c_int8", ("int16_t", True, 0): "c_int16", + ("__int16_t", True, 0): "c_int16", ("__int16", True, 0): "c_int16", ("int32_t", True, 0): "c_int32", + ("__int32_t", True, 0): "c_int32", ("__int32", True, 0): "c_int32", ("int64_t", True, 0): "c_int64", ("__int64", True, 0): "c_int64", - ("uint8_t", True, 0): "c_uint8", - ("uint16_t", True, 0): "c_uint16", - ("uint32_t", True, 0): "c_uint32", - ("uint64_t", True, 0): "c_uint64", + ("__int64_t", True, 0): "c_int64", + ("uint8_t", False, 0): "c_uint8", + ("__uint8", False, 0): "c_uint8", + ("__uint8_t", False, 0): "c_uint8", + ("uint16_t", False, 0): "c_uint16", + ("__uint16", False, 0): "c_uint16", + ("__uint16_t", False, 0): "c_uint16", + ("uint32_t", False, 0): "c_uint32", + ("__uint32", False, 0): "c_uint32", + ("__uint32_t", False, 0): "c_uint32", + ("uint64_t", False, 0): "c_uint64", + ("__uint64", False, 0): "c_uint64", + ("__uint64_t", False, 0): "c_uint64", ("_Bool", True, 0): "c_bool", } ctypes_type_map_python_builtin = { + ("int", True, -1): "c_short", + ("int", False, -1): "c_ushort", ("int", True, 2): "c_longlong", ("int", False, 2): "c_ulonglong", ("size_t", True, 0): "c_size_t", ("apr_int64_t", True, 0): "c_int64", ("off64_t", True, 0): "c_int64", - ("apr_uint64_t", True, 0): "c_uint64", + ("apr_uint64_t", False, 0): "c_uint64", ("wchar_t", True, 0): "c_wchar", ("ptrdiff_t", True, 0): "c_ptrdiff_t", # Requires definition in preamble ("ssize_t", True, 0): "c_ptrdiff_t", # Requires definition in preamble diff --git a/python/libgrass_interface_generator/ctypesgen/parser/cgrammar.py b/python/libgrass_interface_generator/ctypesgen/parser/cgrammar.py index 3205b559375..56fef3795e9 100755 --- a/python/libgrass_interface_generator/ctypesgen/parser/cgrammar.py +++ b/python/libgrass_interface_generator/ctypesgen/parser/cgrammar.py @@ -41,7 +41,7 @@ reserved_keyword_tokens = ( - "SIZEOF", "TYPEDEF", "EXTERN", "STATIC", "AUTO", "REGISTER", # "INLINE", + "SIZEOF", "TYPEDEF", "EXTERN", "STATIC", "AUTO", "REGISTER", "INLINE", "CONST", "RESTRICT", "VOLATILE", "CHAR", "SHORT", "INT", "LONG", "SIGNED", "UNSIGNED", "FLOAT", "DOUBLE", "VOID", "STRUCT", "UNION", "ENUM", @@ -51,16 +51,18 @@ ) reserved_keyword_tokens_new = ( - "_BOOL", + "_BOOL", "_NORETURN", # "_ALIGNAS", "_ALIGNOF", "_ATOMIC", "_COMPLEX", # "_DECIMAL128", "_DECIMAL32", "_DECIMAL64", - # "_GENERIC", "_IMAGINARY", "_NORETURN", "_STATIC_ASSERT", "_THREAD_LOCAL", + # "_GENERIC", "_IMAGINARY", "_STATIC_ASSERT", "_THREAD_LOCAL", ) extra_keywords_with_alias = { "__asm__": "__ASM__", "__attribute__": "__ATTRIBUTE__", "__restrict": "RESTRICT", + "__inline__": "INLINE", + "__inline": "INLINE", } keyword_map = {} @@ -650,6 +652,7 @@ def p_declaration_specifier(p): """ declaration_specifier : storage_class_specifier | type_specifier | type_qualifier + | function_specifier """ p[0] = p[1] @@ -916,6 +919,12 @@ def p_type_qualifier(p): p[0] = cdeclarations.TypeQualifier(p[1]) +def p_function_specifier(p): + """ function_specifier : INLINE + | _NORETURN + """ + + def p_declarator(p): """ declarator : pointer direct_declarator | direct_declarator @@ -1367,6 +1376,7 @@ def p_error(t): def p_pragma(p): """ pragma : pragma_pack + | PRAGMA pragma_directive_list PRAGMA_END """ @@ -1420,5 +1430,22 @@ def p_pragma_pack_stack_args(p): p[0] = (op, id, n) +def p_pragma_directive_list(p): + """ pragma_directive_list : pragma_directive + | pragma_directive_list pragma_directive + """ + if len(p) == 3: + p[0] = p[1] + (p[2],) + else: + p[0] = (p[1],) + + +def p_pragma_directive(p): + """ pragma_directive : IDENTIFIER + | string_literal + """ + p[0] = p[1] + + def main(): yacc.yacc(tabmodule="new_parsetab") diff --git a/python/libgrass_interface_generator/ctypesgen/parser/ctypesparser.py b/python/libgrass_interface_generator/ctypesgen/parser/ctypesparser.py index 5d8dd306662..f92ee080bd7 100644 --- a/python/libgrass_interface_generator/ctypesgen/parser/ctypesparser.py +++ b/python/libgrass_interface_generator/ctypesgen/parser/ctypesparser.py @@ -130,6 +130,8 @@ def get_ctypes_type(self, typ, declarator, check_qualifiers=False): signed = False elif specifier == "long": longs += 1 + elif specifier == "short": + longs = -1 else: typename = str(specifier) diff --git a/python/libgrass_interface_generator/ctypesgen/parser/parsetab.py b/python/libgrass_interface_generator/ctypesgen/parser/parsetab.py index 6578b79cbc7..ab7fae0ae80 100644 --- a/python/libgrass_interface_generator/ctypesgen/parser/parsetab.py +++ b/python/libgrass_interface_generator/ctypesgen/parser/parsetab.py @@ -6,9 +6,9 @@ _lr_method = 'LALR' -_lr_signature = 'nonassocIFnonassocELSEADD_ASSIGN AND AND_ASSIGN AND_OP AUTO BREAK CASE CHAR CHARACTER_CONSTANT COLON COMMA CONDOP CONST CONTINUE DEC_OP DEFAULT DIVIDE DIV_ASSIGN DO DOUBLE ELLIPSIS ELSE ENUM EQUALS EQ_OP EXTERN FLOAT FOR F_CONST_1 F_CONST_2 F_CONST_3 F_CONST_4 F_CONST_5 F_CONST_6 GE_OP GOTO GT IDENTIFIER IF INC_OP INT I_CONST_BIN I_CONST_DEC I_CONST_HEX I_CONST_OCT LBRACE LBRACKET LEFT_ASSIGN LEFT_OP LE_OP LNOT LONG LPAREN LT MINUS MOD MOD_ASSIGN MUL_ASSIGN NE_OP NOT OR OR_ASSIGN OR_OP PERIOD PLUS PP_DEFINE PP_DEFINE_MACRO_NAME PP_DEFINE_NAME PP_END_DEFINE PP_IDENTIFIER_PASTE PP_MACRO_PARAM PP_STRINGIFY PP_UNDEFINE PRAGMA PRAGMA_END PRAGMA_PACK PTR_OP RBRACE RBRACKET REGISTER RESTRICT RETURN RIGHT_ASSIGN RIGHT_OP RPAREN SEMI SHORT SIGNED SIZEOF STATIC STRING_LITERAL STRUCT SUB_ASSIGN SWITCH TIMES TYPEDEF TYPE_NAME UNION UNSIGNED VOID VOLATILE WHILE XOR XOR_ASSIGN _BOOL __ASM__ __ATTRIBUTE__ translation_unit :\n | translation_unit external_declaration\n | translation_unit directive\n identifier : IDENTIFIER\n | IDENTIFIER PP_IDENTIFIER_PASTE identifier\n | PP_MACRO_PARAM PP_IDENTIFIER_PASTE identifier\n | IDENTIFIER PP_IDENTIFIER_PASTE PP_MACRO_PARAM\n | PP_MACRO_PARAM PP_IDENTIFIER_PASTE PP_MACRO_PARAM\n constant : I_CONST_HEX\n | I_CONST_DEC\n | I_CONST_OCT\n | I_CONST_BIN\n constant : F_CONST_1\n | F_CONST_2\n | F_CONST_3\n | F_CONST_4\n | F_CONST_5\n | F_CONST_6\n constant : CHARACTER_CONSTANT\n string_literal : STRING_LITERAL\n multi_string_literal : string_literal\n | macro_param\n | multi_string_literal string_literal\n | multi_string_literal macro_param\n macro_param : PP_MACRO_PARAM\n | PP_STRINGIFY PP_MACRO_PARAM\n primary_expression : identifier\n | constant\n | multi_string_literal\n | LPAREN expression RPAREN\n postfix_expression : primary_expression\n | postfix_expression LBRACKET expression RBRACKET\n | postfix_expression LPAREN RPAREN\n | postfix_expression LPAREN argument_expression_list RPAREN\n | postfix_expression PERIOD IDENTIFIER\n | postfix_expression PTR_OP IDENTIFIER\n | postfix_expression INC_OP\n | postfix_expression DEC_OP\n argument_expression_list : assignment_expression\n | argument_expression_list COMMA assignment_expression\n | type_name\n | argument_expression_list COMMA type_name\n asm_expression : __ASM__ volatile_opt LPAREN string_literal RPAREN\n | __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list RPAREN\n | __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list RPAREN\n | __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list RPAREN\n str_opt_expr_pair_list :\n | str_opt_expr_pair\n | str_opt_expr_pair_list COMMA str_opt_expr_pair\n str_opt_expr_pair : string_literal\n | string_literal LPAREN expression RPAREN\n volatile_opt :\n | VOLATILE\n unary_expression : postfix_expression\n | INC_OP unary_expression\n | DEC_OP unary_expression\n | unary_operator cast_expression\n | SIZEOF unary_expression\n | SIZEOF LPAREN type_name RPAREN\n | asm_expression\n unary_operator : AND\n | TIMES\n | PLUS\n | MINUS\n | NOT\n | LNOT\n cast_expression : unary_expression\n | LPAREN type_name RPAREN cast_expression\n multiplicative_expression : cast_expression\n | multiplicative_expression TIMES cast_expression\n | multiplicative_expression DIVIDE cast_expression\n | multiplicative_expression MOD cast_expression\n additive_expression : multiplicative_expression\n | additive_expression PLUS multiplicative_expression\n | additive_expression MINUS multiplicative_expression\n shift_expression : additive_expression\n | shift_expression LEFT_OP additive_expression\n | shift_expression RIGHT_OP additive_expression\n relational_expression : shift_expression\n | relational_expression LT shift_expression\n | relational_expression GT shift_expression\n | relational_expression LE_OP shift_expression\n | relational_expression GE_OP shift_expression\n equality_expression : relational_expression\n | equality_expression EQ_OP relational_expression\n | equality_expression NE_OP relational_expression\n and_expression : equality_expression\n | and_expression AND equality_expression\n exclusive_or_expression : and_expression\n | exclusive_or_expression XOR and_expression\n inclusive_or_expression : exclusive_or_expression\n | inclusive_or_expression OR exclusive_or_expression\n logical_and_expression : inclusive_or_expression\n | logical_and_expression AND_OP inclusive_or_expression\n logical_or_expression : logical_and_expression\n | logical_or_expression OR_OP logical_and_expression\n conditional_expression : logical_or_expression\n | logical_or_expression CONDOP expression COLON conditional_expression\n assignment_expression : conditional_expression\n | unary_expression assignment_operator assignment_expression\n assignment_operator : EQUALS\n | MUL_ASSIGN\n | DIV_ASSIGN\n | MOD_ASSIGN\n | ADD_ASSIGN\n | SUB_ASSIGN\n | LEFT_ASSIGN\n | RIGHT_ASSIGN\n | AND_ASSIGN\n | XOR_ASSIGN\n | OR_ASSIGN\n expression : assignment_expression\n | expression COMMA assignment_expression\n constant_expression : conditional_expression\n declaration : declaration_impl SEMI\n declaration_impl : declaration_specifier_list\n | declaration_specifier_list init_declarator_list\n declaration_specifier_list : gcc_attributes declaration_specifier gcc_attributes\n | declaration_specifier_list declaration_specifier gcc_attributes\n declaration_specifier : storage_class_specifier\n | type_specifier\n | type_qualifier\n init_declarator_list : init_declarator\n | init_declarator_list COMMA init_declarator\n init_declarator : declarator gcc_attributes\n | declarator gcc_attributes EQUALS initializer\n storage_class_specifier : TYPEDEF\n | EXTERN\n | STATIC\n | AUTO\n | REGISTER\n type_specifier : VOID\n | _BOOL\n | CHAR\n | SHORT\n | INT\n | LONG\n | FLOAT\n | DOUBLE\n | SIGNED\n | UNSIGNED\n | struct_or_union_specifier\n | enum_specifier\n | TYPE_NAME\n struct_or_union_specifier : struct_or_union gcc_attributes IDENTIFIER LBRACE member_declaration_list RBRACE\n | struct_or_union gcc_attributes TYPE_NAME LBRACE member_declaration_list RBRACE\n | struct_or_union gcc_attributes LBRACE member_declaration_list RBRACE\n | struct_or_union gcc_attributes IDENTIFIER\n | struct_or_union gcc_attributes TYPE_NAME\n struct_or_union : STRUCT\n | UNION\n gcc_attributes :\n | gcc_attributes gcc_attribute\n gcc_attribute : __ATTRIBUTE__ LPAREN LPAREN gcc_attrib_list RPAREN RPAREN\n gcc_attrib_list : gcc_attrib\n | gcc_attrib_list COMMA gcc_attrib\n gcc_attrib :\n | IDENTIFIER\n | IDENTIFIER LPAREN argument_expression_list RPAREN\n member_declaration_list : member_declaration\n | member_declaration_list member_declaration\n member_declaration : specifier_qualifier_list member_declarator_list SEMI\n | specifier_qualifier_list SEMI\n specifier_qualifier_list : gcc_attributes specifier_qualifier gcc_attributes\n | specifier_qualifier_list specifier_qualifier gcc_attributes\n specifier_qualifier : type_specifier\n | type_qualifier\n member_declarator_list : member_declarator\n | member_declarator_list COMMA member_declarator\n member_declarator : declarator gcc_attributes\n | COLON constant_expression gcc_attributes\n | declarator COLON constant_expression gcc_attributes\n enum_specifier : ENUM LBRACE enumerator_list RBRACE\n | ENUM IDENTIFIER LBRACE enumerator_list RBRACE\n | ENUM IDENTIFIER\n enumerator_list : enumerator_list_iso\n | enumerator_list_iso COMMA\n enumerator_list_iso : enumerator\n | enumerator_list_iso COMMA enumerator\n enumerator : IDENTIFIER\n | IDENTIFIER EQUALS constant_expression\n type_qualifier : CONST\n | VOLATILE\n | RESTRICT\n declarator : pointer direct_declarator\n | direct_declarator\n direct_declarator : IDENTIFIER\n | LPAREN gcc_attributes declarator RPAREN\n | direct_declarator LBRACKET constant_expression RBRACKET\n | direct_declarator LBRACKET RBRACKET\n | direct_declarator LPAREN parameter_type_list RPAREN\n | direct_declarator LPAREN identifier_list RPAREN\n | direct_declarator LPAREN RPAREN\n pointer : TIMES\n | TIMES type_qualifier_list\n | TIMES pointer\n | TIMES type_qualifier_list pointer\n type_qualifier_list : type_qualifier\n | gcc_attribute\n | type_qualifier_list type_qualifier\n | type_qualifier_list gcc_attribute\n parameter_type_list : parameter_list\n | parameter_list COMMA ELLIPSIS\n parameter_list : parameter_declaration\n | parameter_list COMMA parameter_declaration\n parameter_declaration : declaration_specifier_list declarator gcc_attributes\n | declaration_specifier_list abstract_declarator\n | declaration_specifier_list\n identifier_list : IDENTIFIER\n | identifier_list COMMA IDENTIFIER\n type_name : specifier_qualifier_list\n | specifier_qualifier_list abstract_declarator\n abstract_declarator : pointer\n | direct_abstract_declarator gcc_attributes\n | pointer direct_abstract_declarator gcc_attributes\n direct_abstract_declarator : LPAREN gcc_attributes abstract_declarator RPAREN\n | LBRACKET RBRACKET\n | LBRACKET constant_expression RBRACKET\n | direct_abstract_declarator LBRACKET RBRACKET\n | direct_abstract_declarator LBRACKET constant_expression RBRACKET\n | LPAREN RPAREN\n | LPAREN parameter_type_list RPAREN\n | direct_abstract_declarator LPAREN RPAREN\n | direct_abstract_declarator LPAREN parameter_type_list RPAREN\n initializer : assignment_expression\n | LBRACE initializer_list RBRACE\n | LBRACE initializer_list COMMA RBRACE\n initializer_list : initializer\n | initializer_list COMMA initializer\n statement : labeled_statement\n | compound_statement\n | expression_statement\n | selection_statement\n | iteration_statement\n | jump_statement\n labeled_statement : IDENTIFIER COLON statement\n | CASE constant_expression COLON statement\n | DEFAULT COLON statement\n compound_statement : LBRACE RBRACE\n | LBRACE statement_list RBRACE\n | LBRACE declaration_list RBRACE\n | LBRACE declaration_list statement_list RBRACE\n compound_statement : LBRACE error RBRACE\n declaration_list : declaration\n | declaration_list declaration\n statement_list : statement\n | statement_list statement\n expression_statement : SEMI\n | expression SEMI\n expression_statement : error SEMI\n selection_statement : IF LPAREN expression RPAREN statement %prec IF\n | IF LPAREN expression RPAREN statement ELSE statement\n | SWITCH LPAREN expression RPAREN statement\n iteration_statement : WHILE LPAREN expression RPAREN statement\n | DO statement WHILE LPAREN expression RPAREN SEMI\n | FOR LPAREN expression_statement expression_statement RPAREN statement\n | FOR LPAREN expression_statement expression_statement expression RPAREN statement\n jump_statement : GOTO IDENTIFIER SEMI\n | CONTINUE SEMI\n | BREAK SEMI\n | RETURN SEMI\n | RETURN expression SEMI\n external_declaration : declaration\n | function_definition\n function_definition : declaration_specifier_list declarator declaration_list compound_statement\n | declaration_specifier_list declarator compound_statement\n | declarator declaration_list compound_statement\n | declarator compound_statement\n directive : define\n | undefine\n | pragma\n define : PP_DEFINE PP_DEFINE_NAME PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_NAME type_name PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_NAME constant_expression PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN RPAREN PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN RPAREN constant_expression PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN macro_parameter_list RPAREN PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN macro_parameter_list RPAREN constant_expression PP_END_DEFINE\n define : PP_DEFINE error PP_END_DEFINE\n undefine : PP_UNDEFINE PP_DEFINE_NAME PP_END_DEFINE\n macro_parameter_list : PP_MACRO_PARAM\n | macro_parameter_list COMMA PP_MACRO_PARAM\n pragma : pragma_pack\n pragma_pack : PRAGMA PRAGMA_PACK LPAREN RPAREN PRAGMA_END\n | PRAGMA PRAGMA_PACK LPAREN constant RPAREN PRAGMA_END\n | PRAGMA PRAGMA_PACK LPAREN pragma_pack_stack_args RPAREN PRAGMA_END\n pragma_pack_stack_args : IDENTIFIER\n | IDENTIFIER COMMA IDENTIFIER\n | IDENTIFIER COMMA IDENTIFIER COMMA constant\n | IDENTIFIER COMMA constant COMMA IDENTIFIER\n | IDENTIFIER COMMA constant\n ' +_lr_signature = 'nonassocIFnonassocELSEADD_ASSIGN AND AND_ASSIGN AND_OP AUTO BREAK CASE CHAR CHARACTER_CONSTANT COLON COMMA CONDOP CONST CONTINUE DEC_OP DEFAULT DIVIDE DIV_ASSIGN DO DOUBLE ELLIPSIS ELSE ENUM EQUALS EQ_OP EXTERN FLOAT FOR F_CONST_1 F_CONST_2 F_CONST_3 F_CONST_4 F_CONST_5 F_CONST_6 GE_OP GOTO GT IDENTIFIER IF INC_OP INLINE INT I_CONST_BIN I_CONST_DEC I_CONST_HEX I_CONST_OCT LBRACE LBRACKET LEFT_ASSIGN LEFT_OP LE_OP LNOT LONG LPAREN LT MINUS MOD MOD_ASSIGN MUL_ASSIGN NE_OP NOT OR OR_ASSIGN OR_OP PERIOD PLUS PP_DEFINE PP_DEFINE_MACRO_NAME PP_DEFINE_NAME PP_END_DEFINE PP_IDENTIFIER_PASTE PP_MACRO_PARAM PP_STRINGIFY PP_UNDEFINE PRAGMA PRAGMA_END PRAGMA_PACK PTR_OP RBRACE RBRACKET REGISTER RESTRICT RETURN RIGHT_ASSIGN RIGHT_OP RPAREN SEMI SHORT SIGNED SIZEOF STATIC STRING_LITERAL STRUCT SUB_ASSIGN SWITCH TIMES TYPEDEF TYPE_NAME UNION UNSIGNED VOID VOLATILE WHILE XOR XOR_ASSIGN _BOOL _NORETURN __ASM__ __ATTRIBUTE__ translation_unit :\n | translation_unit external_declaration\n | translation_unit directive\n identifier : IDENTIFIER\n | IDENTIFIER PP_IDENTIFIER_PASTE identifier\n | PP_MACRO_PARAM PP_IDENTIFIER_PASTE identifier\n | IDENTIFIER PP_IDENTIFIER_PASTE PP_MACRO_PARAM\n | PP_MACRO_PARAM PP_IDENTIFIER_PASTE PP_MACRO_PARAM\n constant : I_CONST_HEX\n | I_CONST_DEC\n | I_CONST_OCT\n | I_CONST_BIN\n constant : F_CONST_1\n | F_CONST_2\n | F_CONST_3\n | F_CONST_4\n | F_CONST_5\n | F_CONST_6\n constant : CHARACTER_CONSTANT\n string_literal : STRING_LITERAL\n multi_string_literal : string_literal\n | macro_param\n | multi_string_literal string_literal\n | multi_string_literal macro_param\n macro_param : PP_MACRO_PARAM\n | PP_STRINGIFY PP_MACRO_PARAM\n primary_expression : identifier\n | constant\n | multi_string_literal\n | LPAREN expression RPAREN\n postfix_expression : primary_expression\n | postfix_expression LBRACKET expression RBRACKET\n | postfix_expression LPAREN RPAREN\n | postfix_expression LPAREN argument_expression_list RPAREN\n | postfix_expression PERIOD IDENTIFIER\n | postfix_expression PTR_OP IDENTIFIER\n | postfix_expression INC_OP\n | postfix_expression DEC_OP\n argument_expression_list : assignment_expression\n | argument_expression_list COMMA assignment_expression\n | type_name\n | argument_expression_list COMMA type_name\n asm_expression : __ASM__ volatile_opt LPAREN string_literal RPAREN\n | __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list RPAREN\n | __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list RPAREN\n | __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list RPAREN\n str_opt_expr_pair_list :\n | str_opt_expr_pair\n | str_opt_expr_pair_list COMMA str_opt_expr_pair\n str_opt_expr_pair : string_literal\n | string_literal LPAREN expression RPAREN\n volatile_opt :\n | VOLATILE\n unary_expression : postfix_expression\n | INC_OP unary_expression\n | DEC_OP unary_expression\n | unary_operator cast_expression\n | SIZEOF unary_expression\n | SIZEOF LPAREN type_name RPAREN\n | asm_expression\n unary_operator : AND\n | TIMES\n | PLUS\n | MINUS\n | NOT\n | LNOT\n cast_expression : unary_expression\n | LPAREN type_name RPAREN cast_expression\n multiplicative_expression : cast_expression\n | multiplicative_expression TIMES cast_expression\n | multiplicative_expression DIVIDE cast_expression\n | multiplicative_expression MOD cast_expression\n additive_expression : multiplicative_expression\n | additive_expression PLUS multiplicative_expression\n | additive_expression MINUS multiplicative_expression\n shift_expression : additive_expression\n | shift_expression LEFT_OP additive_expression\n | shift_expression RIGHT_OP additive_expression\n relational_expression : shift_expression\n | relational_expression LT shift_expression\n | relational_expression GT shift_expression\n | relational_expression LE_OP shift_expression\n | relational_expression GE_OP shift_expression\n equality_expression : relational_expression\n | equality_expression EQ_OP relational_expression\n | equality_expression NE_OP relational_expression\n and_expression : equality_expression\n | and_expression AND equality_expression\n exclusive_or_expression : and_expression\n | exclusive_or_expression XOR and_expression\n inclusive_or_expression : exclusive_or_expression\n | inclusive_or_expression OR exclusive_or_expression\n logical_and_expression : inclusive_or_expression\n | logical_and_expression AND_OP inclusive_or_expression\n logical_or_expression : logical_and_expression\n | logical_or_expression OR_OP logical_and_expression\n conditional_expression : logical_or_expression\n | logical_or_expression CONDOP expression COLON conditional_expression\n assignment_expression : conditional_expression\n | unary_expression assignment_operator assignment_expression\n assignment_operator : EQUALS\n | MUL_ASSIGN\n | DIV_ASSIGN\n | MOD_ASSIGN\n | ADD_ASSIGN\n | SUB_ASSIGN\n | LEFT_ASSIGN\n | RIGHT_ASSIGN\n | AND_ASSIGN\n | XOR_ASSIGN\n | OR_ASSIGN\n expression : assignment_expression\n | expression COMMA assignment_expression\n constant_expression : conditional_expression\n declaration : declaration_impl SEMI\n declaration_impl : declaration_specifier_list\n | declaration_specifier_list init_declarator_list\n declaration_specifier_list : gcc_attributes declaration_specifier gcc_attributes\n | declaration_specifier_list declaration_specifier gcc_attributes\n declaration_specifier : storage_class_specifier\n | type_specifier\n | type_qualifier\n | function_specifier\n init_declarator_list : init_declarator\n | init_declarator_list COMMA init_declarator\n init_declarator : declarator gcc_attributes\n | declarator gcc_attributes EQUALS initializer\n storage_class_specifier : TYPEDEF\n | EXTERN\n | STATIC\n | AUTO\n | REGISTER\n type_specifier : VOID\n | _BOOL\n | CHAR\n | SHORT\n | INT\n | LONG\n | FLOAT\n | DOUBLE\n | SIGNED\n | UNSIGNED\n | struct_or_union_specifier\n | enum_specifier\n | TYPE_NAME\n struct_or_union_specifier : struct_or_union gcc_attributes IDENTIFIER LBRACE member_declaration_list RBRACE\n | struct_or_union gcc_attributes TYPE_NAME LBRACE member_declaration_list RBRACE\n | struct_or_union gcc_attributes LBRACE member_declaration_list RBRACE\n | struct_or_union gcc_attributes IDENTIFIER\n | struct_or_union gcc_attributes TYPE_NAME\n struct_or_union : STRUCT\n | UNION\n gcc_attributes :\n | gcc_attributes gcc_attribute\n gcc_attribute : __ATTRIBUTE__ LPAREN LPAREN gcc_attrib_list RPAREN RPAREN\n gcc_attrib_list : gcc_attrib\n | gcc_attrib_list COMMA gcc_attrib\n gcc_attrib :\n | IDENTIFIER\n | IDENTIFIER LPAREN argument_expression_list RPAREN\n member_declaration_list : member_declaration\n | member_declaration_list member_declaration\n member_declaration : specifier_qualifier_list member_declarator_list SEMI\n | specifier_qualifier_list SEMI\n specifier_qualifier_list : gcc_attributes specifier_qualifier gcc_attributes\n | specifier_qualifier_list specifier_qualifier gcc_attributes\n specifier_qualifier : type_specifier\n | type_qualifier\n member_declarator_list : member_declarator\n | member_declarator_list COMMA member_declarator\n member_declarator : declarator gcc_attributes\n | COLON constant_expression gcc_attributes\n | declarator COLON constant_expression gcc_attributes\n enum_specifier : ENUM LBRACE enumerator_list RBRACE\n | ENUM IDENTIFIER LBRACE enumerator_list RBRACE\n | ENUM IDENTIFIER\n enumerator_list : enumerator_list_iso\n | enumerator_list_iso COMMA\n enumerator_list_iso : enumerator\n | enumerator_list_iso COMMA enumerator\n enumerator : IDENTIFIER\n | IDENTIFIER EQUALS constant_expression\n type_qualifier : CONST\n | VOLATILE\n | RESTRICT\n function_specifier : INLINE\n | _NORETURN\n declarator : pointer direct_declarator\n | direct_declarator\n direct_declarator : IDENTIFIER\n | LPAREN gcc_attributes declarator RPAREN\n | direct_declarator LBRACKET constant_expression RBRACKET\n | direct_declarator LBRACKET RBRACKET\n | direct_declarator LPAREN parameter_type_list RPAREN\n | direct_declarator LPAREN identifier_list RPAREN\n | direct_declarator LPAREN RPAREN\n pointer : TIMES\n | TIMES type_qualifier_list\n | TIMES pointer\n | TIMES type_qualifier_list pointer\n type_qualifier_list : type_qualifier\n | gcc_attribute\n | type_qualifier_list type_qualifier\n | type_qualifier_list gcc_attribute\n parameter_type_list : parameter_list\n | parameter_list COMMA ELLIPSIS\n parameter_list : parameter_declaration\n | parameter_list COMMA parameter_declaration\n parameter_declaration : declaration_specifier_list declarator gcc_attributes\n | declaration_specifier_list abstract_declarator\n | declaration_specifier_list\n identifier_list : IDENTIFIER\n | identifier_list COMMA IDENTIFIER\n type_name : specifier_qualifier_list\n | specifier_qualifier_list abstract_declarator\n abstract_declarator : pointer\n | direct_abstract_declarator gcc_attributes\n | pointer direct_abstract_declarator gcc_attributes\n direct_abstract_declarator : LPAREN gcc_attributes abstract_declarator RPAREN\n | LBRACKET RBRACKET\n | LBRACKET constant_expression RBRACKET\n | direct_abstract_declarator LBRACKET RBRACKET\n | direct_abstract_declarator LBRACKET constant_expression RBRACKET\n | LPAREN RPAREN\n | LPAREN parameter_type_list RPAREN\n | direct_abstract_declarator LPAREN RPAREN\n | direct_abstract_declarator LPAREN parameter_type_list RPAREN\n initializer : assignment_expression\n | LBRACE initializer_list RBRACE\n | LBRACE initializer_list COMMA RBRACE\n initializer_list : initializer\n | initializer_list COMMA initializer\n statement : labeled_statement\n | compound_statement\n | expression_statement\n | selection_statement\n | iteration_statement\n | jump_statement\n labeled_statement : IDENTIFIER COLON statement\n | CASE constant_expression COLON statement\n | DEFAULT COLON statement\n compound_statement : LBRACE RBRACE\n | LBRACE statement_list RBRACE\n | LBRACE declaration_list RBRACE\n | LBRACE declaration_list statement_list RBRACE\n compound_statement : LBRACE error RBRACE\n declaration_list : declaration\n | declaration_list declaration\n statement_list : statement\n | statement_list statement\n expression_statement : SEMI\n | expression SEMI\n expression_statement : error SEMI\n selection_statement : IF LPAREN expression RPAREN statement %prec IF\n | IF LPAREN expression RPAREN statement ELSE statement\n | SWITCH LPAREN expression RPAREN statement\n iteration_statement : WHILE LPAREN expression RPAREN statement\n | DO statement WHILE LPAREN expression RPAREN SEMI\n | FOR LPAREN expression_statement expression_statement RPAREN statement\n | FOR LPAREN expression_statement expression_statement expression RPAREN statement\n jump_statement : GOTO IDENTIFIER SEMI\n | CONTINUE SEMI\n | BREAK SEMI\n | RETURN SEMI\n | RETURN expression SEMI\n external_declaration : declaration\n | function_definition\n function_definition : declaration_specifier_list declarator declaration_list compound_statement\n | declaration_specifier_list declarator compound_statement\n | declarator declaration_list compound_statement\n | declarator compound_statement\n directive : define\n | undefine\n | pragma\n define : PP_DEFINE PP_DEFINE_NAME PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_NAME type_name PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_NAME constant_expression PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN RPAREN PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN RPAREN constant_expression PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN macro_parameter_list RPAREN PP_END_DEFINE\n | PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN macro_parameter_list RPAREN constant_expression PP_END_DEFINE\n define : PP_DEFINE error PP_END_DEFINE\n undefine : PP_UNDEFINE PP_DEFINE_NAME PP_END_DEFINE\n macro_parameter_list : PP_MACRO_PARAM\n | macro_parameter_list COMMA PP_MACRO_PARAM\n pragma : pragma_pack\n | PRAGMA pragma_directive_list PRAGMA_END\n pragma_pack : PRAGMA PRAGMA_PACK LPAREN RPAREN PRAGMA_END\n | PRAGMA PRAGMA_PACK LPAREN constant RPAREN PRAGMA_END\n | PRAGMA PRAGMA_PACK LPAREN pragma_pack_stack_args RPAREN PRAGMA_END\n pragma_pack_stack_args : IDENTIFIER\n | IDENTIFIER COMMA IDENTIFIER\n | IDENTIFIER COMMA IDENTIFIER COMMA constant\n | IDENTIFIER COMMA constant COMMA IDENTIFIER\n | IDENTIFIER COMMA constant\n pragma_directive_list : pragma_directive\n | pragma_directive_list pragma_directive\n pragma_directive : IDENTIFIER\n | string_literal\n ' -_lr_action_items = {'PP_DEFINE':([0,1,2,3,4,5,6,7,8,15,22,56,77,84,86,160,170,172,188,199,202,204,275,276,316,374,386,425,426,432,433,459,],[-1,12,-2,-3,-263,-264,-269,-270,-271,-283,-115,-268,-266,-267,-239,-272,-279,-280,-265,-240,-241,-243,-273,-274,-242,-275,-284,-276,-277,-285,-286,-278,]),'PP_UNDEFINE':([0,1,2,3,4,5,6,7,8,15,22,56,77,84,86,160,170,172,188,199,202,204,275,276,316,374,386,425,426,432,433,459,],[-1,14,-2,-3,-263,-264,-269,-270,-271,-283,-115,-268,-266,-267,-239,-272,-279,-280,-265,-240,-241,-243,-273,-274,-242,-275,-284,-276,-277,-285,-286,-278,]),'PRAGMA':([0,1,2,3,4,5,6,7,8,15,22,56,77,84,86,160,170,172,188,199,202,204,275,276,316,374,386,425,426,432,433,459,],[-1,19,-2,-3,-263,-264,-269,-270,-271,-283,-115,-268,-266,-267,-239,-272,-279,-280,-265,-240,-241,-243,-273,-274,-242,-275,-284,-276,-277,-285,-286,-278,]),'TIMES':([0,1,2,3,4,5,6,7,8,10,13,15,20,22,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,56,57,58,59,60,63,65,66,69,72,74,75,77,79,80,83,84,85,86,87,88,90,91,92,93,94,95,96,97,98,99,103,106,111,114,116,117,118,119,120,121,122,124,125,126,127,128,129,130,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,158,160,163,166,167,168,170,172,173,183,186,187,188,189,191,193,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,242,243,244,245,246,247,248,249,250,253,254,255,256,257,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,275,276,278,281,282,283,284,285,286,299,306,310,312,314,316,317,318,319,320,321,324,325,329,330,331,336,340,341,347,348,358,359,360,361,362,363,366,368,373,374,376,385,386,393,399,403,404,405,406,407,408,409,410,411,412,413,414,415,425,426,431,432,433,437,438,440,442,444,445,446,447,449,454,459,460,470,472,473,481,482,483,484,486,493,495,],[-1,20,-2,-3,-263,-264,-269,-270,-271,20,-152,-283,20,-115,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-268,-244,126,20,126,20,-152,-153,126,20,-198,-199,-266,20,-119,-175,-267,-245,-239,126,126,-246,-230,-231,-232,-233,-234,-235,-248,-4,126,126,126,126,-67,-54,126,126,126,-69,126,-60,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,271,-272,20,-67,126,-4,-279,-280,-118,20,-200,-201,-265,126,-148,-149,-240,-247,-241,126,-243,-250,126,126,-249,126,126,126,126,126,-259,-260,-261,126,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,126,126,126,126,-37,-38,-55,126,-56,-57,-58,126,126,126,-23,-24,-25,126,126,-26,126,126,126,126,126,126,126,126,126,126,126,126,126,-273,-274,-152,-166,-167,-152,126,-152,126,-152,126,20,-173,126,-242,-236,-5,-7,126,-238,-30,126,126,-258,-262,-33,-35,-36,-8,-6,271,271,-70,-71,-72,-165,126,20,-164,-275,126,20,-284,-147,126,-174,-237,126,-68,126,126,126,126,126,-32,-34,126,-59,-276,-277,126,-285,-286,126,-145,20,126,-146,-251,-253,-254,126,-43,-278,-154,126,-256,126,-252,-255,-257,126,-44,-45,-46,]),'IDENTIFIER':([0,1,2,3,4,5,6,7,8,10,13,15,17,20,22,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,63,65,66,69,70,72,73,74,75,77,79,80,81,82,83,84,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,108,111,117,118,119,121,125,126,127,128,129,130,160,167,170,172,173,183,184,185,186,187,188,189,191,193,198,199,200,202,203,204,205,206,207,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,245,249,250,253,257,258,259,261,262,263,264,265,266,267,268,269,270,271,272,273,275,276,278,281,282,284,285,286,290,294,298,299,306,310,312,313,314,316,317,320,321,325,329,330,331,363,366,373,374,376,385,386,389,393,399,403,404,405,407,408,409,410,411,414,425,426,430,431,432,433,437,438,440,442,444,445,446,447,449,459,460,464,470,472,473,481,482,483,484,],[-1,21,-2,-3,-263,-264,-269,-270,-271,21,-152,-283,21,-194,-115,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,83,-150,-151,-268,-244,98,21,168,21,-152,-153,168,181,-195,-196,-198,-199,-266,21,-119,191,197,-175,-267,-245,-239,98,98,-246,-230,-231,-232,-233,-234,-235,-248,168,168,98,219,168,168,168,168,168,-61,-62,-63,-64,-65,-66,-272,168,-279,-280,-118,21,303,-197,-200,-201,-265,168,-148,-149,197,-240,-247,-241,98,-243,-250,98,168,98,-249,168,168,168,168,168,-259,-260,-261,168,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,168,168,168,168,340,341,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,-273,-274,-152,-166,-167,168,-152,168,380,381,21,-152,168,21,-173,197,168,-242,-236,98,-238,168,168,-258,-262,-165,168,-164,-275,168,21,-284,434,-147,168,-174,-237,98,98,98,168,168,168,168,-276,-277,380,168,-285,-286,168,-145,21,168,-146,-251,-253,-254,98,-278,-154,479,98,-256,98,-252,-255,-257,168,]),'LPAREN':([0,1,2,3,4,5,6,7,8,10,13,15,17,18,20,21,22,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,56,57,58,59,60,61,63,65,66,67,68,69,71,72,73,74,75,77,79,80,83,84,85,86,87,88,90,91,92,93,94,95,96,97,98,99,102,103,104,105,106,107,111,116,117,118,119,121,124,125,126,127,128,129,130,131,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,160,163,167,168,170,172,173,174,176,178,183,185,186,187,188,189,191,193,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,242,243,245,249,250,251,252,253,254,255,256,257,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,275,276,278,279,280,281,282,283,284,285,286,289,291,292,293,298,299,306,310,312,314,316,317,318,319,320,321,324,325,328,329,330,331,336,340,341,347,348,363,364,366,368,369,371,373,374,376,380,385,386,393,399,403,404,405,407,408,409,410,411,412,413,414,418,420,423,424,425,426,431,432,433,437,438,440,442,444,445,446,447,449,456,457,458,459,460,470,472,473,474,481,482,483,484,],[-1,13,-2,-3,-263,-264,-269,-270,-271,13,-152,-283,13,70,-194,-187,-115,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-268,-244,103,13,167,169,13,-152,-153,174,70,167,184,-195,-196,-198,-199,-266,13,-119,-175,-267,-245,-239,103,103,-246,-230,-231,-232,-233,-234,-235,-248,-4,167,212,103,215,216,103,218,103,239,245,245,167,249,-31,-61,-62,-63,-64,-65,-66,-52,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-272,283,103,-4,-279,-280,-118,290,-190,-193,299,-197,-200,-201,-265,103,-148,-149,-240,-247,-241,103,-243,-250,103,103,-249,103,103,103,103,103,-259,-260,-261,103,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,103,167,103,103,-37,-38,103,103,167,344,-53,167,-23,-24,-25,167,167,-26,167,167,167,167,167,167,167,167,167,167,167,167,167,-273,-274,-152,283,367,-166,-167,-152,167,-152,167,-188,-189,-191,-192,299,-152,103,13,-173,167,-242,-236,-5,-7,103,-238,-30,167,409,103,-258,-262,-33,-35,-36,-8,-6,-165,367,167,283,-221,-217,-164,-275,167,431,299,-284,-147,167,-174,-237,103,103,103,103,103,167,-32,-34,103,-219,-223,-222,-218,-276,-277,103,-285,-286,103,-145,13,167,-146,-251,-253,-254,103,-220,-224,-216,-278,-154,103,-256,103,484,-252,-255,-257,103,]),'$end':([0,1,2,3,4,5,6,7,8,15,22,56,77,84,86,160,170,172,188,199,202,204,275,276,316,374,386,425,426,432,433,459,],[-1,0,-2,-3,-263,-264,-269,-270,-271,-283,-115,-268,-266,-267,-239,-272,-279,-280,-265,-240,-241,-243,-273,-274,-242,-275,-284,-276,-277,-285,-286,-278,]),'__ATTRIBUTE__':([0,1,2,3,4,5,6,7,8,11,13,15,16,18,20,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53,54,55,56,57,58,60,63,65,66,68,70,72,74,75,76,77,78,80,81,83,84,85,86,88,103,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,159,160,164,165,166,167,168,170,172,173,176,178,186,187,188,191,192,193,199,202,204,239,242,243,244,246,247,248,249,254,255,256,260,274,275,276,278,280,281,282,283,285,289,291,292,293,295,296,299,307,308,309,311,312,316,318,319,324,334,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,367,368,369,371,373,374,384,385,386,392,393,394,396,398,400,403,406,412,413,414,415,417,418,420,423,424,425,426,431,432,433,438,439,441,443,444,451,454,456,457,458,459,460,468,469,480,486,493,495,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,-152,-152,-283,67,-186,67,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-150,-151,-152,-268,-244,-152,-152,67,-152,-153,-185,-152,67,-198,-199,-152,-266,67,67,67,-175,-267,-245,-239,-152,-152,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-152,-272,-114,67,-67,-152,-4,-279,-280,67,-190,-193,-200,-201,-265,-148,-152,-149,-240,-241,-243,-152,-37,-38,-55,-56,-57,-58,-152,-23,-24,-25,-26,67,-273,-274,-152,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-152,-160,-152,-173,-242,-5,-7,-30,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,67,-152,67,-152,67,-221,-217,67,-275,67,67,-284,-152,-147,-161,-163,-152,-152,-174,-68,-32,-34,-152,-59,67,-219,-223,-222,-218,-276,-277,-152,-285,-286,-145,-162,67,-152,-146,-98,-43,-220,-224,-216,-278,-154,-152,67,67,-44,-45,-46,]),'TYPEDEF':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,65,66,68,70,76,77,78,80,83,84,85,86,88,160,170,172,173,176,178,183,188,191,193,199,202,204,275,276,283,289,291,292,293,295,299,312,316,367,368,374,385,386,393,403,425,426,432,433,438,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,30,-152,-283,30,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,30,-152,-153,-185,-152,-152,-266,30,-119,-175,-267,-245,-239,-152,-272,-279,-280,-118,-190,-193,30,-265,-148,-149,-240,-241,-243,-273,-274,-152,-188,-189,-191,-192,-152,-152,-173,-242,-152,30,-275,30,-284,-147,-174,-276,-277,-285,-286,-145,-146,-278,-154,]),'EXTERN':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,65,66,68,70,76,77,78,80,83,84,85,86,88,160,170,172,173,176,178,183,188,191,193,199,202,204,275,276,283,289,291,292,293,295,299,312,316,367,368,374,385,386,393,403,425,426,432,433,438,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,31,-152,-283,31,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,31,-152,-153,-185,-152,-152,-266,31,-119,-175,-267,-245,-239,-152,-272,-279,-280,-118,-190,-193,31,-265,-148,-149,-240,-241,-243,-273,-274,-152,-188,-189,-191,-192,-152,-152,-173,-242,-152,31,-275,31,-284,-147,-174,-276,-277,-285,-286,-145,-146,-278,-154,]),'STATIC':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,65,66,68,70,76,77,78,80,83,84,85,86,88,160,170,172,173,176,178,183,188,191,193,199,202,204,275,276,283,289,291,292,293,295,299,312,316,367,368,374,385,386,393,403,425,426,432,433,438,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,32,-152,-283,32,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,32,-152,-153,-185,-152,-152,-266,32,-119,-175,-267,-245,-239,-152,-272,-279,-280,-118,-190,-193,32,-265,-148,-149,-240,-241,-243,-273,-274,-152,-188,-189,-191,-192,-152,-152,-173,-242,-152,32,-275,32,-284,-147,-174,-276,-277,-285,-286,-145,-146,-278,-154,]),'AUTO':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,65,66,68,70,76,77,78,80,83,84,85,86,88,160,170,172,173,176,178,183,188,191,193,199,202,204,275,276,283,289,291,292,293,295,299,312,316,367,368,374,385,386,393,403,425,426,432,433,438,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,33,-152,-283,33,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,33,-152,-153,-185,-152,-152,-266,33,-119,-175,-267,-245,-239,-152,-272,-279,-280,-118,-190,-193,33,-265,-148,-149,-240,-241,-243,-273,-274,-152,-188,-189,-191,-192,-152,-152,-173,-242,-152,33,-275,33,-284,-147,-174,-276,-277,-285,-286,-145,-146,-278,-154,]),'REGISTER':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,65,66,68,70,76,77,78,80,83,84,85,86,88,160,170,172,173,176,178,183,188,191,193,199,202,204,275,276,283,289,291,292,293,295,299,312,316,367,368,374,385,386,393,403,425,426,432,433,438,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,34,-152,-283,34,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,34,-152,-153,-185,-152,-152,-266,34,-119,-175,-267,-245,-239,-152,-272,-279,-280,-118,-190,-193,34,-265,-148,-149,-240,-241,-243,-273,-274,-152,-188,-189,-191,-192,-152,-152,-173,-242,-152,34,-275,34,-284,-147,-174,-276,-277,-285,-286,-145,-146,-278,-154,]),'VOID':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,35,-152,-283,35,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,35,-152,-152,-153,-185,-152,-152,-266,35,-119,-175,-267,-245,-239,-152,-152,-272,35,35,-152,-279,-280,-118,-190,-193,35,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,35,-152,-173,-242,-165,-152,35,-164,-275,35,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'_BOOL':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,36,-152,-283,36,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,36,-152,-152,-153,-185,-152,-152,-266,36,-119,-175,-267,-245,-239,-152,-152,-272,36,36,-152,-279,-280,-118,-190,-193,36,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,36,-152,-173,-242,-165,-152,36,-164,-275,36,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'CHAR':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,37,-152,-283,37,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,37,-152,-152,-153,-185,-152,-152,-266,37,-119,-175,-267,-245,-239,-152,-152,-272,37,37,-152,-279,-280,-118,-190,-193,37,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,37,-152,-173,-242,-165,-152,37,-164,-275,37,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'SHORT':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,38,-152,-283,38,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,38,-152,-152,-153,-185,-152,-152,-266,38,-119,-175,-267,-245,-239,-152,-152,-272,38,38,-152,-279,-280,-118,-190,-193,38,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,38,-152,-173,-242,-165,-152,38,-164,-275,38,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'INT':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,39,-152,-283,39,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,39,-152,-152,-153,-185,-152,-152,-266,39,-119,-175,-267,-245,-239,-152,-152,-272,39,39,-152,-279,-280,-118,-190,-193,39,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,39,-152,-173,-242,-165,-152,39,-164,-275,39,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'LONG':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,40,-152,-283,40,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,40,-152,-152,-153,-185,-152,-152,-266,40,-119,-175,-267,-245,-239,-152,-152,-272,40,40,-152,-279,-280,-118,-190,-193,40,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,40,-152,-173,-242,-165,-152,40,-164,-275,40,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'FLOAT':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,41,-152,-283,41,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,41,-152,-152,-153,-185,-152,-152,-266,41,-119,-175,-267,-245,-239,-152,-152,-272,41,41,-152,-279,-280,-118,-190,-193,41,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,41,-152,-173,-242,-165,-152,41,-164,-275,41,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'DOUBLE':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,42,-152,-283,42,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,42,-152,-152,-153,-185,-152,-152,-266,42,-119,-175,-267,-245,-239,-152,-152,-272,42,42,-152,-279,-280,-118,-190,-193,42,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,42,-152,-173,-242,-165,-152,42,-164,-275,42,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'SIGNED':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,43,-152,-283,43,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,43,-152,-152,-153,-185,-152,-152,-266,43,-119,-175,-267,-245,-239,-152,-152,-272,43,43,-152,-279,-280,-118,-190,-193,43,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,43,-152,-173,-242,-165,-152,43,-164,-275,43,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'UNSIGNED':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,44,-152,-283,44,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,44,-152,-152,-153,-185,-152,-152,-266,44,-119,-175,-267,-245,-239,-152,-152,-272,44,44,-152,-279,-280,-118,-190,-193,44,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,44,-152,-173,-242,-165,-152,44,-164,-275,44,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'TYPE_NAME':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53,54,55,56,57,58,59,60,65,66,68,70,76,77,78,80,81,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,47,-152,-283,47,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-150,-151,-152,-268,-244,-152,47,-152,-152,-153,-185,-152,-152,-266,47,-119,193,-175,-267,-245,-239,-152,-152,-272,47,47,-152,-279,-280,-118,-190,-193,47,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,47,-152,-173,-242,-165,-152,47,-164,-275,47,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'CONST':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,20,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,72,74,75,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,186,187,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,48,-152,-283,48,-186,48,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,48,-152,-152,-153,-185,-152,48,-198,-199,-152,-266,48,-119,-175,-267,-245,-239,-152,-152,-272,48,48,-152,-279,-280,-118,-190,-193,48,-200,-201,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,48,-152,-173,-242,-165,-152,48,-164,-275,48,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'VOLATILE':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,20,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,72,74,75,76,77,78,80,83,84,85,86,88,103,131,160,163,165,167,170,172,173,176,178,183,186,187,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,49,-152,-283,49,-186,49,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,49,-152,-152,-153,-185,-152,49,-198,-199,-152,-266,49,-119,-175,-267,-245,-239,-152,-152,252,-272,49,49,-152,-279,-280,-118,-190,-193,49,-200,-201,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,49,-152,-173,-242,-165,-152,49,-164,-275,49,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'RESTRICT':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,20,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,72,74,75,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,186,187,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,50,-152,-283,50,-186,50,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,50,-152,-152,-153,-185,-152,50,-198,-199,-152,-266,50,-119,-175,-267,-245,-239,-152,-152,-272,50,50,-152,-279,-280,-118,-190,-193,50,-200,-201,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,50,-152,-173,-242,-165,-152,50,-164,-275,50,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'ENUM':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,52,-152,-283,52,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,52,-152,-152,-153,-185,-152,-152,-266,52,-119,-175,-267,-245,-239,-152,-152,-272,52,52,-152,-279,-280,-118,-190,-193,52,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,52,-152,-173,-242,-165,-152,52,-164,-275,52,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'STRUCT':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,53,-152,-283,53,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,53,-152,-152,-153,-185,-152,-152,-266,53,-119,-175,-267,-245,-239,-152,-152,-272,53,53,-152,-279,-280,-118,-190,-193,53,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,53,-152,-173,-242,-165,-152,53,-164,-275,53,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'UNION':([0,1,2,3,4,5,6,7,8,10,11,15,16,18,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,65,66,68,70,76,77,78,80,83,84,85,86,88,103,160,163,165,167,170,172,173,176,178,183,188,191,192,193,199,202,204,239,249,275,276,278,281,282,283,285,289,291,292,293,295,299,307,308,309,310,311,312,316,363,367,368,373,374,385,386,392,393,394,396,400,403,414,425,426,431,432,433,438,439,444,459,460,],[-1,-152,-2,-3,-263,-264,-269,-270,-271,54,-152,-283,54,-186,-187,-115,-152,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-268,-244,-152,54,-152,-152,-153,-185,-152,-152,-266,54,-119,-175,-267,-245,-239,-152,-152,-272,54,54,-152,-279,-280,-118,-190,-193,54,-265,-148,-152,-149,-240,-241,-243,-152,-152,-273,-274,-152,-166,-167,-152,-152,-188,-189,-191,-192,-152,-152,-152,-152,-160,54,-152,-173,-242,-165,-152,54,-164,-275,54,-284,-152,-147,-161,-163,-152,-174,-152,-276,-277,-152,-285,-286,-145,-162,-146,-278,-154,]),'SEMI':([9,10,18,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,57,58,59,65,66,68,78,80,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,101,106,109,110,111,112,113,114,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,159,164,166,168,173,176,178,190,191,193,199,200,201,202,203,204,205,206,209,210,218,219,220,221,222,223,242,243,244,246,247,248,254,255,256,260,274,278,281,282,285,289,291,292,293,304,305,310,312,316,317,318,319,320,321,322,324,329,330,331,332,334,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,373,393,395,397,398,403,404,405,406,407,408,412,413,415,436,438,441,443,444,445,446,447,449,451,454,460,465,467,468,469,470,471,472,473,480,481,482,483,486,493,495,],[22,-116,-186,-187,-115,-152,-117,-152,-123,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-244,97,-116,-152,-153,-185,-125,-119,-175,-245,-239,97,97,205,-246,-230,-231,-232,-233,-234,-235,-248,-4,210,97,220,221,222,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-152,-114,-67,-4,-118,-190,-193,-124,-148,-149,-240,-247,205,-241,97,-243,-250,97,97,-249,97,330,-259,-260,-261,331,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-125,-152,-166,-167,-152,-188,-189,-191,-192,-126,-225,396,-173,-242,-236,-5,-7,97,-238,-113,-30,97,-258,-262,-100,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-165,-164,-147,439,-168,-152,-174,-237,97,-68,97,97,-32,-34,-59,-226,-145,-170,-152,-146,-251,-253,-254,97,-98,-43,-154,-227,-169,-152,-171,97,482,-256,97,-172,-252,-255,-257,-44,-45,-46,]),'LBRACE':([11,18,21,22,23,51,52,53,54,55,57,58,66,68,76,81,83,85,86,87,88,90,91,92,93,94,95,96,97,106,176,178,189,191,193,199,200,202,203,204,205,206,209,210,220,221,222,289,291,292,293,306,316,317,320,321,330,331,404,405,407,408,437,445,446,447,449,460,470,472,473,481,482,483,],[58,-186,-187,-115,58,-152,82,-150,-151,58,-244,58,-153,-185,58,192,198,-245,-239,58,58,-246,-230,-231,-232,-233,-234,-235,-248,58,-190,-193,306,307,311,-240,-247,-241,58,-243,-250,58,58,-249,-259,-260,-261,-188,-189,-191,-192,306,-242,-236,58,-238,-258,-262,-237,58,58,58,306,-251,-253,-254,58,-154,58,-256,58,-252,-255,-257,]),'PP_DEFINE_NAME':([12,14,],[60,64,]),'PP_DEFINE_MACRO_NAME':([12,],[61,]),'error':([12,22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,218,220,221,222,316,317,320,321,329,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[62,-115,-244,89,-245,-239,201,201,-246,-230,-231,-232,-233,-234,-235,-248,201,-240,-247,-241,201,-243,-250,201,201,-249,201,-259,-260,-261,-242,-236,201,-238,201,-258,-262,-237,201,201,201,-251,-253,-254,201,201,-256,201,-252,-255,-257,]),'EQUALS':([18,21,23,66,68,78,98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,159,166,168,176,178,197,242,243,244,246,247,248,254,255,256,260,274,289,291,292,293,318,319,324,336,340,341,347,348,406,412,413,415,454,460,486,493,495,],[-186,-187,-152,-153,-185,189,-4,225,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-152,-67,-4,-190,-193,314,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,189,-188,-189,-191,-192,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-154,-44,-45,-46,]),'COMMA':([18,20,21,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,65,66,68,72,73,74,75,78,80,83,98,101,112,113,114,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,159,163,164,166,168,173,176,178,179,180,181,182,183,185,186,187,190,191,193,195,196,197,213,223,242,243,244,246,247,248,254,255,256,260,274,277,278,279,280,281,282,285,287,288,289,290,291,292,293,296,297,298,303,304,305,312,318,319,322,323,324,326,327,332,333,334,335,336,337,338,339,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,369,371,373,378,379,380,381,383,384,390,391,393,395,397,398,401,402,403,406,412,413,415,417,418,420,423,424,428,430,434,435,436,438,441,443,444,448,450,451,452,453,454,455,456,457,458,460,461,462,465,466,467,468,469,474,475,476,477,480,485,486,488,489,490,491,492,493,494,495,],[-186,-194,-187,-152,79,-152,-123,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-153,-185,-195,-196,-198,-199,-125,-119,-175,-4,211,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-152,-211,-114,-67,-4,-118,-190,-193,294,295,-209,-204,-208,-197,-200,-201,-124,-148,-149,313,-178,-180,211,211,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-125,-212,-152,-213,-152,-166,-167,-152,377,-281,-188,-157,-189,-191,-192,-152,-207,-213,389,-126,-225,-173,-5,-7,-113,211,-30,211,211,-100,211,-96,211,-33,414,-39,-41,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-165,-152,-214,-221,-217,-164,430,-155,-158,-210,-205,-206,437,-228,-147,440,-168,-152,-179,-181,-174,-68,-32,-34,-59,-215,-219,-223,-222,-218,-282,-157,463,464,-226,-145,-170,-152,-146,211,211,-98,-40,-42,-43,-47,-220,-224,-216,-154,-156,414,-227,-229,-169,-152,-171,-50,487,-48,-159,-172,-47,-44,211,487,-49,-51,-47,-45,487,-46,]),'RPAREN':([18,20,21,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,65,66,68,70,72,73,74,75,80,83,97,112,113,114,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,163,166,168,169,171,173,176,177,178,179,180,181,182,183,184,185,186,187,191,193,205,210,213,214,239,242,243,244,246,247,248,254,255,256,260,277,278,279,280,281,282,283,285,287,288,289,290,291,292,293,296,297,298,299,301,302,303,312,318,319,322,323,324,326,327,332,334,336,337,338,339,340,341,342,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,367,369,370,371,373,378,379,380,381,382,383,384,393,403,406,410,412,413,415,416,417,418,420,421,422,423,424,428,429,430,434,435,438,444,448,450,451,452,453,454,455,456,457,458,460,461,462,474,475,476,477,478,479,485,486,488,489,490,491,492,493,494,495,],[-186,-194,-187,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-153,-185,178,-195,-196,-198,-199,-119,-175,-248,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-211,-67,-4,286,289,-118,-190,292,-193,293,-202,-209,-204,-208,300,-197,-200,-201,-148,-149,-250,-249,324,325,336,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-212,-152,-213,-152,-166,-167,369,-152,376,-281,-188,-157,-189,-191,-192,-152,-207,-213,369,387,388,-287,-173,-5,-7,-113,405,-30,407,408,-100,-96,-33,413,-39,-41,-35,-36,415,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-165,-152,-214,420,-221,423,-217,-164,429,-155,-158,-210,-203,-205,-206,-147,-174,-68,449,-32,-34,-59,454,-215,-219,-223,457,458,-222,-218,-282,460,-157,-288,-291,-145,-146,471,473,-98,-40,-42,-43,-47,-220,-224,-216,-154,-156,477,-50,486,-48,-159,-289,-290,-47,-44,491,493,-49,-51,-47,-45,495,-46,]),'COLON':([18,21,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,66,68,83,98,100,112,113,114,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,164,166,168,176,178,191,193,208,242,243,244,246,247,248,254,255,256,260,278,281,282,285,289,291,292,293,310,312,318,319,322,324,332,333,334,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,373,393,398,403,406,412,413,415,416,438,440,444,451,454,455,460,474,475,476,485,486,489,490,491,493,495,],[-186,-187,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-153,-185,-175,206,209,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-114,-67,-4,-190,-193,-148,-149,320,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-152,-166,-167,-152,-188,-189,-191,-192,399,-173,-5,-7,-113,-30,-100,411,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-165,-164,-147,442,-174,-68,-32,-34,-59,455,-145,399,-146,-98,-43,-47,-154,-50,485,-48,-47,-44,492,-49,-51,-45,-46,]),'LBRACKET':([18,20,21,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,65,66,68,72,73,74,75,80,83,98,116,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,163,168,173,176,178,183,185,186,187,191,193,242,243,254,255,256,260,278,279,280,281,282,283,285,289,291,292,293,298,299,312,318,319,324,336,340,341,347,348,363,364,368,369,371,373,385,393,403,412,413,418,420,423,424,438,444,456,457,458,460,],[69,-194,-187,-152,-120,-121,-122,-127,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,-152,-153,69,-195,-196,-198,-199,-119,-175,-4,238,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,284,-4,-118,-190,-193,284,-197,-200,-201,-148,-149,-37,-38,-23,-24,-25,-26,-152,284,366,-166,-167,-152,-152,-188,-189,-191,-192,284,-152,-173,-5,-7,-30,-33,-35,-36,-8,-6,-165,366,284,-221,-217,-164,284,-147,-174,-32,-34,-219,-223,-222,-218,-145,-146,-220,-224,-216,-154,]),'PRAGMA_PACK':([19,],[71,]),'PP_END_DEFINE':([20,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,60,62,64,66,72,73,74,75,83,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,161,162,163,164,166,168,185,186,187,191,193,242,243,244,246,247,248,254,255,256,260,277,278,279,280,281,282,285,286,312,318,319,324,334,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,369,371,373,375,376,393,403,406,412,413,415,417,418,420,423,424,427,438,444,451,454,456,457,458,460,486,493,495,],[-194,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-182,-183,-184,160,170,172,-153,-195,-196,-198,-199,-175,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,275,276,-211,-114,-67,-4,-197,-200,-201,-148,-149,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-212,-152,-213,-152,-166,-167,-152,374,-173,-5,-7,-30,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-165,-152,-214,-221,-217,-164,425,426,-147,-174,-68,-32,-34,-59,-215,-219,-223,-222,-218,459,-145,-146,-98,-43,-220,-224,-216,-154,-44,-45,-46,]),'RBRACE':([22,57,58,85,86,87,88,89,90,91,92,93,94,95,96,97,113,114,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,164,166,168,194,195,196,197,199,200,202,203,204,205,210,220,221,222,242,243,244,246,247,248,254,255,256,260,305,308,309,313,315,316,317,318,319,321,324,330,331,332,334,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,390,391,392,394,396,400,401,402,404,406,412,413,415,436,437,439,445,446,447,451,454,465,466,472,481,482,483,486,493,495,],[-115,-244,86,-245,-239,199,202,204,-246,-230,-231,-232,-233,-234,-235,-248,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-114,-67,-4,312,-176,-178,-180,-240,-247,-241,316,-243,-250,-249,-259,-260,-261,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-225,393,-160,-177,403,-242,-236,-5,-7,-238,-30,-258,-262,-100,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,436,-228,438,-161,-163,444,-179,-181,-237,-68,-32,-34,-59,-226,465,-162,-251,-253,-254,-98,-43,-227,-229,-256,-252,-255,-257,-44,-45,-46,]),'CASE':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,99,-245,-239,99,99,-246,-230,-231,-232,-233,-234,-235,-248,99,-240,-247,-241,99,-243,-250,99,99,-249,-259,-260,-261,-242,-236,99,-238,-258,-262,-237,99,99,99,-251,-253,-254,99,99,-256,99,-252,-255,-257,]),'DEFAULT':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,100,-245,-239,100,100,-246,-230,-231,-232,-233,-234,-235,-248,100,-240,-247,-241,100,-243,-250,100,100,-249,-259,-260,-261,-242,-236,100,-238,-258,-262,-237,100,100,100,-251,-253,-254,100,100,-256,100,-252,-255,-257,]),'IF':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,102,-245,-239,102,102,-246,-230,-231,-232,-233,-234,-235,-248,102,-240,-247,-241,102,-243,-250,102,102,-249,-259,-260,-261,-242,-236,102,-238,-258,-262,-237,102,102,102,-251,-253,-254,102,102,-256,102,-252,-255,-257,]),'SWITCH':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,104,-245,-239,104,104,-246,-230,-231,-232,-233,-234,-235,-248,104,-240,-247,-241,104,-243,-250,104,104,-249,-259,-260,-261,-242,-236,104,-238,-258,-262,-237,104,104,104,-251,-253,-254,104,104,-256,104,-252,-255,-257,]),'WHILE':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,217,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,105,-245,-239,105,105,-246,-230,-231,-232,-233,-234,-235,-248,105,-240,-247,-241,105,-243,-250,105,105,-249,328,-259,-260,-261,-242,-236,105,-238,-258,-262,-237,105,105,105,-251,-253,-254,105,105,-256,105,-252,-255,-257,]),'DO':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,106,-245,-239,106,106,-246,-230,-231,-232,-233,-234,-235,-248,106,-240,-247,-241,106,-243,-250,106,106,-249,-259,-260,-261,-242,-236,106,-238,-258,-262,-237,106,106,106,-251,-253,-254,106,106,-256,106,-252,-255,-257,]),'FOR':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,107,-245,-239,107,107,-246,-230,-231,-232,-233,-234,-235,-248,107,-240,-247,-241,107,-243,-250,107,107,-249,-259,-260,-261,-242,-236,107,-238,-258,-262,-237,107,107,107,-251,-253,-254,107,107,-256,107,-252,-255,-257,]),'GOTO':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,108,-245,-239,108,108,-246,-230,-231,-232,-233,-234,-235,-248,108,-240,-247,-241,108,-243,-250,108,108,-249,-259,-260,-261,-242,-236,108,-238,-258,-262,-237,108,108,108,-251,-253,-254,108,108,-256,108,-252,-255,-257,]),'CONTINUE':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,109,-245,-239,109,109,-246,-230,-231,-232,-233,-234,-235,-248,109,-240,-247,-241,109,-243,-250,109,109,-249,-259,-260,-261,-242,-236,109,-238,-258,-262,-237,109,109,109,-251,-253,-254,109,109,-256,109,-252,-255,-257,]),'BREAK':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,110,-245,-239,110,110,-246,-230,-231,-232,-233,-234,-235,-248,110,-240,-247,-241,110,-243,-250,110,110,-249,-259,-260,-261,-242,-236,110,-238,-258,-262,-237,110,110,110,-251,-253,-254,110,110,-256,110,-252,-255,-257,]),'RETURN':([22,57,58,85,86,87,88,90,91,92,93,94,95,96,97,106,199,200,202,203,204,205,206,209,210,220,221,222,316,317,320,321,330,331,404,405,407,408,445,446,447,449,470,472,473,481,482,483,],[-115,-244,111,-245,-239,111,111,-246,-230,-231,-232,-233,-234,-235,-248,111,-240,-247,-241,111,-243,-250,111,111,-249,-259,-260,-261,-242,-236,111,-238,-258,-262,-237,111,111,111,-251,-253,-254,111,111,-256,111,-252,-255,-257,]),'INC_OP':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,98,99,103,106,111,116,117,118,119,121,124,125,126,127,128,129,130,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,167,168,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,242,243,245,249,250,253,254,255,256,257,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,318,319,320,321,324,325,329,330,331,336,340,341,347,348,366,376,399,404,405,407,408,409,410,411,412,413,414,431,437,442,445,446,447,449,470,472,473,481,482,483,484,],[-115,-244,117,117,117,-245,-239,117,117,-246,-230,-231,-232,-233,-234,-235,-248,-4,117,117,117,117,242,117,117,117,117,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,117,-4,117,-240,-247,-241,117,-243,-250,117,117,-249,117,117,117,117,117,-259,-260,-261,117,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,117,117,117,117,-37,-38,117,117,117,117,-23,-24,-25,117,117,-26,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,-242,-236,-5,-7,117,-238,-30,117,117,-258,-262,-33,-35,-36,-8,-6,117,117,117,-237,117,117,117,117,117,117,-32,-34,117,117,117,117,-251,-253,-254,117,117,-256,117,-252,-255,-257,117,]),'DEC_OP':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,98,99,103,106,111,116,117,118,119,121,124,125,126,127,128,129,130,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,167,168,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,242,243,245,249,250,253,254,255,256,257,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,318,319,320,321,324,325,329,330,331,336,340,341,347,348,366,376,399,404,405,407,408,409,410,411,412,413,414,431,437,442,445,446,447,449,470,472,473,481,482,483,484,],[-115,-244,118,118,118,-245,-239,118,118,-246,-230,-231,-232,-233,-234,-235,-248,-4,118,118,118,118,243,118,118,118,118,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,118,-4,118,-240,-247,-241,118,-243,-250,118,118,-249,118,118,118,118,118,-259,-260,-261,118,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,118,118,118,118,-37,-38,118,118,118,118,-23,-24,-25,118,118,-26,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,-242,-236,-5,-7,118,-238,-30,118,118,-258,-262,-33,-35,-36,-8,-6,118,118,118,-237,118,118,118,118,118,118,-32,-34,118,118,118,118,-251,-253,-254,118,118,-256,118,-252,-255,-257,118,]),'SIZEOF':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,470,472,473,481,482,483,484,],[-115,-244,121,121,121,-245,-239,121,121,-246,-230,-231,-232,-233,-234,-235,-248,121,121,121,121,121,121,121,121,-61,-62,-63,-64,-65,-66,121,121,-240,-247,-241,121,-243,-250,121,121,-249,121,121,121,121,121,-259,-260,-261,121,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,-242,-236,121,-238,121,121,-258,-262,121,121,121,-237,121,121,121,121,121,121,121,121,121,121,-251,-253,-254,121,121,-256,121,-252,-255,-257,121,]),'AND':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,98,99,103,106,111,114,116,117,118,119,120,121,122,124,125,126,127,128,129,130,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,166,167,168,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,242,243,244,245,246,247,248,249,250,253,254,255,256,257,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,318,319,320,321,324,325,329,330,331,336,340,341,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,366,376,399,404,405,406,407,408,409,410,411,412,413,414,415,431,437,442,445,446,447,449,454,470,472,473,481,482,483,484,486,493,495,],[-115,-244,125,125,125,-245,-239,125,125,-246,-230,-231,-232,-233,-234,-235,-248,-4,125,125,125,125,-67,-54,125,125,125,-69,125,-60,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,259,-20,-87,-84,-79,-76,-73,-67,125,-4,125,-240,-247,-241,125,-243,-250,125,125,-249,125,125,125,125,125,-259,-260,-261,125,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,125,125,125,125,-37,-38,-55,125,-56,-57,-58,125,125,125,-23,-24,-25,125,125,-26,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-242,-236,-5,-7,125,-238,-30,125,125,-258,-262,-33,-35,-36,259,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,125,125,125,-237,125,-68,125,125,125,125,125,-32,-34,125,-59,125,125,125,-251,-253,-254,125,-43,125,-256,125,-252,-255,-257,125,-44,-45,-46,]),'PLUS':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,98,99,103,106,111,114,116,117,118,119,120,121,122,124,125,126,127,128,129,130,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,157,158,166,167,168,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,242,243,244,245,246,247,248,249,250,253,254,255,256,257,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,318,319,320,321,324,325,329,330,331,336,340,341,347,348,356,357,358,359,360,361,362,366,376,399,404,405,406,407,408,409,410,411,412,413,414,415,431,437,442,445,446,447,449,454,470,472,473,481,482,483,484,486,493,495,],[-115,-244,127,127,127,-245,-239,127,127,-246,-230,-231,-232,-233,-234,-235,-248,-4,127,127,127,127,-67,-54,127,127,127,-69,127,-60,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,269,-73,-67,127,-4,127,-240,-247,-241,127,-243,-250,127,127,-249,127,127,127,127,127,-259,-260,-261,127,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,127,127,127,127,-37,-38,-55,127,-56,-57,-58,127,127,127,-23,-24,-25,127,127,-26,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,-242,-236,-5,-7,127,-238,-30,127,127,-258,-262,-33,-35,-36,-8,-6,269,269,-74,-75,-70,-71,-72,127,127,127,-237,127,-68,127,127,127,127,127,-32,-34,127,-59,127,127,127,-251,-253,-254,127,-43,127,-256,127,-252,-255,-257,127,-44,-45,-46,]),'MINUS':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,98,99,103,106,111,114,116,117,118,119,120,121,122,124,125,126,127,128,129,130,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,157,158,166,167,168,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,242,243,244,245,246,247,248,249,250,253,254,255,256,257,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,318,319,320,321,324,325,329,330,331,336,340,341,347,348,356,357,358,359,360,361,362,366,376,399,404,405,406,407,408,409,410,411,412,413,414,415,431,437,442,445,446,447,449,454,470,472,473,481,482,483,484,486,493,495,],[-115,-244,128,128,128,-245,-239,128,128,-246,-230,-231,-232,-233,-234,-235,-248,-4,128,128,128,128,-67,-54,128,128,128,-69,128,-60,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,270,-73,-67,128,-4,128,-240,-247,-241,128,-243,-250,128,128,-249,128,128,128,128,128,-259,-260,-261,128,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,128,128,128,128,-37,-38,-55,128,-56,-57,-58,128,128,128,-23,-24,-25,128,128,-26,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,-242,-236,-5,-7,128,-238,-30,128,128,-258,-262,-33,-35,-36,-8,-6,270,270,-74,-75,-70,-71,-72,128,128,128,-237,128,-68,128,128,128,128,128,-32,-34,128,-59,128,128,128,-251,-253,-254,128,-43,128,-256,128,-252,-255,-257,128,-44,-45,-46,]),'NOT':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,470,472,473,481,482,483,484,],[-115,-244,129,129,129,-245,-239,129,129,-246,-230,-231,-232,-233,-234,-235,-248,129,129,129,129,129,129,129,129,-61,-62,-63,-64,-65,-66,129,129,-240,-247,-241,129,-243,-250,129,129,-249,129,129,129,129,129,-259,-260,-261,129,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,-242,-236,129,-238,129,129,-258,-262,129,129,129,-237,129,129,129,129,129,129,129,129,129,129,-251,-253,-254,129,129,-256,129,-252,-255,-257,129,]),'LNOT':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,470,472,473,481,482,483,484,],[-115,-244,130,130,130,-245,-239,130,130,-246,-230,-231,-232,-233,-234,-235,-248,130,130,130,130,130,130,130,130,-61,-62,-63,-64,-65,-66,130,130,-240,-247,-241,130,-243,-250,130,130,-249,130,130,130,130,130,-259,-260,-261,130,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,-242,-236,130,-238,130,130,-258,-262,130,130,130,-237,130,130,130,130,130,130,130,130,130,130,-251,-253,-254,130,130,-256,130,-252,-255,-257,130,]),'__ASM__':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,470,472,473,481,482,483,484,],[-115,-244,131,131,131,-245,-239,131,131,-246,-230,-231,-232,-233,-234,-235,-248,131,131,131,131,131,131,131,131,-61,-62,-63,-64,-65,-66,131,131,-240,-247,-241,131,-243,-250,131,131,-249,131,131,131,131,131,-259,-260,-261,131,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,-242,-236,131,-238,131,131,-258,-262,131,131,131,-237,131,131,131,131,131,131,131,131,131,131,-251,-253,-254,131,131,-256,131,-252,-255,-257,131,]),'PP_MACRO_PARAM':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,132,136,138,150,152,153,167,169,189,199,200,202,203,204,205,206,207,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,377,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,470,472,473,481,482,483,484,],[-115,-244,138,138,138,-245,-239,138,138,-246,-230,-231,-232,-233,-234,-235,-248,138,138,138,138,138,138,138,138,-61,-62,-63,-64,-65,-66,-21,256,-25,-22,-20,260,138,288,138,-240,-247,-241,138,-243,-250,138,319,138,-249,138,138,138,138,138,-259,-260,-261,138,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,138,138,138,138,138,138,138,138,-23,-24,-25,138,347,138,-26,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,-242,-236,138,-238,138,138,-258,-262,138,138,428,138,-237,138,138,138,138,138,138,138,138,138,138,-251,-253,-254,138,138,-256,138,-252,-255,-257,138,]),'I_CONST_HEX':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,139,139,139,-245,-239,139,139,-246,-230,-231,-232,-233,-234,-235,-248,139,139,139,139,139,139,139,139,-61,-62,-63,-64,-65,-66,139,139,139,-240,-247,-241,139,-243,-250,139,139,-249,139,139,139,139,139,-259,-260,-261,139,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,-242,-236,139,-238,139,139,-258,-262,139,139,139,139,-237,139,139,139,139,139,139,139,139,139,139,-251,-253,-254,139,139,139,-256,139,-252,-255,-257,139,]),'I_CONST_DEC':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,140,140,140,-245,-239,140,140,-246,-230,-231,-232,-233,-234,-235,-248,140,140,140,140,140,140,140,140,-61,-62,-63,-64,-65,-66,140,140,140,-240,-247,-241,140,-243,-250,140,140,-249,140,140,140,140,140,-259,-260,-261,140,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,-242,-236,140,-238,140,140,-258,-262,140,140,140,140,-237,140,140,140,140,140,140,140,140,140,140,-251,-253,-254,140,140,140,-256,140,-252,-255,-257,140,]),'I_CONST_OCT':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,141,141,141,-245,-239,141,141,-246,-230,-231,-232,-233,-234,-235,-248,141,141,141,141,141,141,141,141,-61,-62,-63,-64,-65,-66,141,141,141,-240,-247,-241,141,-243,-250,141,141,-249,141,141,141,141,141,-259,-260,-261,141,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,-242,-236,141,-238,141,141,-258,-262,141,141,141,141,-237,141,141,141,141,141,141,141,141,141,141,-251,-253,-254,141,141,141,-256,141,-252,-255,-257,141,]),'I_CONST_BIN':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,142,142,142,-245,-239,142,142,-246,-230,-231,-232,-233,-234,-235,-248,142,142,142,142,142,142,142,142,-61,-62,-63,-64,-65,-66,142,142,142,-240,-247,-241,142,-243,-250,142,142,-249,142,142,142,142,142,-259,-260,-261,142,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,-242,-236,142,-238,142,142,-258,-262,142,142,142,142,-237,142,142,142,142,142,142,142,142,142,142,-251,-253,-254,142,142,142,-256,142,-252,-255,-257,142,]),'F_CONST_1':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,143,143,143,-245,-239,143,143,-246,-230,-231,-232,-233,-234,-235,-248,143,143,143,143,143,143,143,143,-61,-62,-63,-64,-65,-66,143,143,143,-240,-247,-241,143,-243,-250,143,143,-249,143,143,143,143,143,-259,-260,-261,143,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,-242,-236,143,-238,143,143,-258,-262,143,143,143,143,-237,143,143,143,143,143,143,143,143,143,143,-251,-253,-254,143,143,143,-256,143,-252,-255,-257,143,]),'F_CONST_2':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,144,144,144,-245,-239,144,144,-246,-230,-231,-232,-233,-234,-235,-248,144,144,144,144,144,144,144,144,-61,-62,-63,-64,-65,-66,144,144,144,-240,-247,-241,144,-243,-250,144,144,-249,144,144,144,144,144,-259,-260,-261,144,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,-242,-236,144,-238,144,144,-258,-262,144,144,144,144,-237,144,144,144,144,144,144,144,144,144,144,-251,-253,-254,144,144,144,-256,144,-252,-255,-257,144,]),'F_CONST_3':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,145,145,145,-245,-239,145,145,-246,-230,-231,-232,-233,-234,-235,-248,145,145,145,145,145,145,145,145,-61,-62,-63,-64,-65,-66,145,145,145,-240,-247,-241,145,-243,-250,145,145,-249,145,145,145,145,145,-259,-260,-261,145,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,-242,-236,145,-238,145,145,-258,-262,145,145,145,145,-237,145,145,145,145,145,145,145,145,145,145,-251,-253,-254,145,145,145,-256,145,-252,-255,-257,145,]),'F_CONST_4':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,146,146,146,-245,-239,146,146,-246,-230,-231,-232,-233,-234,-235,-248,146,146,146,146,146,146,146,146,-61,-62,-63,-64,-65,-66,146,146,146,-240,-247,-241,146,-243,-250,146,146,-249,146,146,146,146,146,-259,-260,-261,146,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,-242,-236,146,-238,146,146,-258,-262,146,146,146,146,-237,146,146,146,146,146,146,146,146,146,146,-251,-253,-254,146,146,146,-256,146,-252,-255,-257,146,]),'F_CONST_5':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,147,147,147,-245,-239,147,147,-246,-230,-231,-232,-233,-234,-235,-248,147,147,147,147,147,147,147,147,-61,-62,-63,-64,-65,-66,147,147,147,-240,-247,-241,147,-243,-250,147,147,-249,147,147,147,147,147,-259,-260,-261,147,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,-242,-236,147,-238,147,147,-258,-262,147,147,147,147,-237,147,147,147,147,147,147,147,147,147,147,-251,-253,-254,147,147,147,-256,147,-252,-255,-257,147,]),'F_CONST_6':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,148,148,148,-245,-239,148,148,-246,-230,-231,-232,-233,-234,-235,-248,148,148,148,148,148,148,148,148,-61,-62,-63,-64,-65,-66,148,148,148,-240,-247,-241,148,-243,-250,148,148,-249,148,148,148,148,148,-259,-260,-261,148,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,-242,-236,148,-238,148,148,-258,-262,148,148,148,148,-237,148,148,148,148,148,148,148,148,148,148,-251,-253,-254,148,148,148,-256,148,-252,-255,-257,148,]),'CHARACTER_CONSTANT':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,167,184,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,389,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,463,470,472,473,481,482,483,484,],[-115,-244,149,149,149,-245,-239,149,149,-246,-230,-231,-232,-233,-234,-235,-248,149,149,149,149,149,149,149,149,-61,-62,-63,-64,-65,-66,149,149,149,-240,-247,-241,149,-243,-250,149,149,-249,149,149,149,149,149,-259,-260,-261,149,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,-242,-236,149,-238,149,149,-258,-262,149,149,149,149,-237,149,149,149,149,149,149,149,149,149,149,-251,-253,-254,149,149,149,-256,149,-252,-255,-257,149,]),'STRING_LITERAL':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,132,136,138,150,152,167,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,254,255,256,257,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,344,366,376,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,455,470,472,473,481,482,483,484,485,487,492,],[-115,-244,152,152,152,-245,-239,152,152,-246,-230,-231,-232,-233,-234,-235,-248,152,152,152,152,152,152,152,152,-61,-62,-63,-64,-65,-66,-21,152,-25,-22,-20,152,152,-240,-247,-241,152,-243,-250,152,152,-249,152,152,152,152,152,-259,-260,-261,152,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,152,152,152,152,152,152,152,152,-23,-24,-25,152,152,-26,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,-242,-236,152,-238,152,152,-258,-262,152,152,152,152,-237,152,152,152,152,152,152,152,152,152,152,-251,-253,-254,152,152,152,-256,152,-252,-255,-257,152,152,152,152,]),'PP_STRINGIFY':([22,57,58,60,69,85,86,87,88,90,91,92,93,94,95,96,97,99,103,106,111,117,118,119,121,125,126,127,128,129,130,132,136,138,150,152,167,189,199,200,202,203,204,205,206,209,210,211,212,215,216,218,220,221,222,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,245,249,250,253,254,255,256,257,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,316,317,320,321,325,329,330,331,366,376,399,404,405,407,408,409,410,411,414,431,437,442,445,446,447,449,470,472,473,481,482,483,484,],[-115,-244,153,153,153,-245,-239,153,153,-246,-230,-231,-232,-233,-234,-235,-248,153,153,153,153,153,153,153,153,-61,-62,-63,-64,-65,-66,-21,153,-25,-22,-20,153,153,-240,-247,-241,153,-243,-250,153,153,-249,153,153,153,153,153,-259,-260,-261,153,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,153,153,153,153,153,153,153,153,-23,-24,-25,153,153,-26,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,-242,-236,153,-238,153,153,-258,-262,153,153,153,-237,153,153,153,153,153,153,153,153,153,153,-251,-253,-254,153,153,-256,153,-252,-255,-257,153,]),'RBRACKET':([69,112,113,114,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,164,166,168,175,242,243,244,246,247,248,254,255,256,260,284,318,319,322,324,332,334,335,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,366,372,406,412,413,415,419,451,454,486,493,495,],[176,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-114,-67,-4,291,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,371,-5,-7,-113,-30,-100,-96,412,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,418,424,-68,-32,-34,-59,456,-98,-43,-44,-45,-46,]),'ELSE':([86,91,92,93,94,95,96,97,199,202,204,205,210,220,221,222,316,317,321,330,331,404,445,446,447,472,481,482,483,],[-239,-230,-231,-232,-233,-234,-235,-248,-240,-241,-243,-250,-249,-259,-260,-261,-242,-236,-238,-258,-262,-237,470,-253,-254,-256,-252,-255,-257,]),'PERIOD':([98,116,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,168,242,243,254,255,256,260,318,319,324,336,340,341,347,348,412,413,],[-4,240,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-4,-37,-38,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-32,-34,]),'PTR_OP':([98,116,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,168,242,243,254,255,256,260,318,319,324,336,340,341,347,348,412,413,],[-4,241,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-4,-37,-38,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-32,-34,]),'MUL_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,226,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'DIV_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,227,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'MOD_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,228,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'ADD_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,229,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'SUB_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,230,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'LEFT_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,231,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'RIGHT_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,232,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'AND_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,233,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'XOR_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,234,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'OR_ASSIGN':([98,114,116,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,406,412,413,415,454,486,493,495,],[-4,235,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'DIVIDE':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,272,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,272,272,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'MOD':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,273,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,273,273,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'LEFT_OP':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,267,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,267,267,267,267,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'RIGHT_OP':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,268,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,268,268,268,268,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'LT':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,263,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,263,263,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'GT':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,264,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,264,264,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'LE_OP':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,265,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,265,265,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'GE_OP':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,266,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,266,266,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'EQ_OP':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,154,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,261,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,261,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'NE_OP':([98,114,116,120,122,124,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,152,154,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-20,262,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,262,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'XOR':([98,114,116,120,122,124,132,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,257,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,257,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'OR':([98,114,116,120,122,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,-31,-21,253,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,253,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'AND_OP':([98,114,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,334,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,-54,-69,-60,250,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,250,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'CONDOP':([98,114,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,334,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,236,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'OR_OP':([98,114,115,116,120,122,123,124,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,154,155,156,157,158,166,168,242,243,244,246,247,248,254,255,256,260,318,319,324,334,336,340,341,343,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,406,412,413,415,454,486,493,495,],[-4,-67,237,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-20,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'PP_IDENTIFIER_PASTE':([98,138,168,319,347,],[207,258,207,258,258,]),'ELLIPSIS':([295,],[382,]),'PRAGMA_END':([300,387,388,],[386,432,433,]),} +_lr_action_items = {'PP_DEFINE':([0,1,2,3,4,5,6,7,8,15,22,59,85,92,94,167,177,179,180,197,208,211,213,284,285,325,383,387,434,435,438,439,468,],[-1,12,-2,-3,-266,-267,-272,-273,-274,-286,-115,-271,-269,-270,-242,-275,-282,-283,-287,-268,-243,-244,-246,-276,-277,-245,-278,-288,-279,-280,-289,-290,-281,]),'PP_UNDEFINE':([0,1,2,3,4,5,6,7,8,15,22,59,85,92,94,167,177,179,180,197,208,211,213,284,285,325,383,387,434,435,438,439,468,],[-1,14,-2,-3,-266,-267,-272,-273,-274,-286,-115,-271,-269,-270,-242,-275,-282,-283,-287,-268,-243,-244,-246,-276,-277,-245,-278,-288,-279,-280,-289,-290,-281,]),'PRAGMA':([0,1,2,3,4,5,6,7,8,15,22,59,85,92,94,167,177,179,180,197,208,211,213,284,285,325,383,387,434,435,438,439,468,],[-1,16,-2,-3,-266,-267,-272,-273,-274,-286,-115,-271,-269,-270,-242,-275,-282,-283,-287,-268,-243,-244,-246,-276,-277,-245,-278,-288,-279,-280,-289,-290,-281,]),'TIMES':([0,1,2,3,4,5,6,7,8,10,13,15,20,22,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,59,60,61,62,63,66,73,74,75,78,80,82,83,85,87,88,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,111,114,119,122,124,125,126,127,128,129,130,132,133,134,135,136,137,138,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,165,167,170,173,174,175,177,179,180,183,193,195,196,197,198,200,202,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,251,252,253,254,255,256,257,258,259,262,263,264,265,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,284,285,287,290,291,292,293,294,295,312,315,319,321,323,325,326,327,328,329,330,333,334,338,339,340,345,349,350,356,357,367,368,369,370,371,372,375,377,382,383,385,387,398,402,408,412,413,414,415,416,417,418,419,420,421,422,423,424,434,435,438,439,444,446,447,449,451,453,454,455,456,458,463,468,471,479,481,482,490,491,492,493,495,502,504,],[-1,20,-2,-3,-266,-267,-272,-273,-274,20,-153,-286,20,-115,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-271,-247,134,20,134,20,-20,-153,-154,134,20,-201,-202,-269,20,-119,-176,-270,-248,-242,134,134,-249,-233,-234,-235,-236,-237,-238,-251,-4,134,134,134,134,-67,-54,134,134,134,-69,134,-60,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,280,-275,20,-67,134,-4,-282,-283,-287,-118,20,-203,-204,-268,134,-149,-150,-243,-250,-244,134,-246,-253,134,134,-252,134,134,134,134,134,-262,-263,-264,134,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,134,134,134,134,-37,-38,-55,134,-56,-57,-58,134,134,134,-23,-24,-25,134,134,-26,134,134,134,134,134,134,134,134,134,134,134,134,134,-276,-277,-153,-167,-168,-153,134,-153,134,-153,134,20,-174,134,-245,-239,-5,-7,134,-241,-30,134,134,-261,-265,-33,-35,-36,-8,-6,280,280,-70,-71,-72,-166,134,20,-165,-278,134,-288,20,-148,134,-175,-240,134,-68,134,134,134,134,134,-32,-34,134,-59,-279,-280,-289,-290,134,134,-146,20,134,-147,-254,-256,-257,134,-43,-281,-155,134,-259,134,-255,-258,-260,134,-44,-45,-46,]),'IDENTIFIER':([0,1,2,3,4,5,6,7,8,10,13,15,16,18,20,22,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,59,60,61,62,63,66,68,70,71,72,73,74,75,78,79,80,81,82,83,85,87,88,89,90,91,92,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,116,119,125,126,127,129,133,134,135,136,137,138,167,174,177,179,180,181,182,183,193,194,195,196,197,198,200,202,207,208,209,211,212,213,214,215,216,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,254,258,259,262,266,267,268,270,271,272,273,274,275,276,277,278,279,280,281,282,284,285,287,290,291,293,294,295,303,307,311,312,315,319,321,322,323,325,326,329,330,334,338,339,340,372,375,382,383,385,387,390,398,402,408,412,413,414,416,417,418,419,420,423,434,435,438,439,443,444,446,447,449,451,453,454,455,456,458,468,470,471,479,481,482,490,491,492,493,],[-1,21,-2,-3,-266,-267,-272,-273,-274,21,-153,-286,71,21,-197,-115,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,91,-151,-152,-271,-247,106,21,175,21,71,-296,-298,-299,-20,-153,-154,175,191,-198,-199,-201,-202,-269,21,-119,200,206,-176,-270,-248,-242,106,106,-249,-233,-234,-235,-236,-237,-238,-251,175,175,106,228,175,175,175,175,175,-61,-62,-63,-64,-65,-66,-275,175,-282,-283,-287,-297,302,-118,21,-200,-203,-204,-268,175,-149,-150,206,-243,-250,-244,106,-246,-253,106,175,106,-252,175,175,175,175,175,-262,-263,-264,175,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,175,175,175,175,349,350,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,-276,-277,-153,-167,-168,175,-153,175,393,394,21,-153,175,21,-174,206,175,-245,-239,106,-241,175,175,-261,-265,-166,175,-165,-278,175,-288,440,21,-148,175,-175,-240,106,106,106,175,175,175,175,-279,-280,-289,-290,393,175,175,-146,21,175,-147,-254,-256,-257,106,-281,487,-155,106,-259,106,-255,-258,-260,175,]),'LPAREN':([0,1,2,3,4,5,6,7,8,10,13,15,18,19,20,21,22,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,59,60,61,62,63,64,66,69,73,74,75,76,77,78,80,81,82,83,85,87,88,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,110,111,112,113,114,115,119,124,125,126,127,129,132,133,134,135,136,137,138,139,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,167,170,174,175,177,179,180,183,184,186,188,193,194,195,196,197,198,200,202,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,251,252,254,258,259,260,261,262,263,264,265,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,284,285,287,288,289,290,291,292,293,294,295,298,304,305,306,311,312,315,319,321,323,325,326,327,328,329,330,333,334,337,338,339,340,345,349,350,356,357,372,373,375,377,378,380,382,383,385,387,393,398,402,408,412,413,414,416,417,418,419,420,421,422,423,427,429,432,433,434,435,438,439,444,446,447,449,451,453,454,455,456,458,465,466,467,468,471,479,481,482,483,490,491,492,493,],[-1,13,-2,-3,-266,-267,-272,-273,-274,13,-153,-286,13,79,-197,-190,-115,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-271,-247,111,13,174,176,13,182,-20,-153,-154,184,79,174,-198,-199,-201,-202,-269,13,-119,-176,-270,-248,-242,111,111,-249,-233,-234,-235,-236,-237,-238,-251,-4,174,221,111,224,225,111,227,111,248,254,254,174,258,-31,-61,-62,-63,-64,-65,-66,-52,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-275,292,111,-4,-282,-283,-287,-118,303,-193,-196,312,-200,-203,-204,-268,111,-149,-150,-243,-250,-244,111,-246,-253,111,111,-252,111,111,111,111,111,-262,-263,-264,111,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,111,174,111,111,-37,-38,111,111,174,353,-53,174,-23,-24,-25,174,174,-26,174,174,174,174,174,174,174,174,174,174,174,174,174,-276,-277,-153,292,376,-167,-168,-153,174,-153,174,-191,-192,-194,-195,312,-153,111,13,-174,174,-245,-239,-5,-7,111,-241,-30,174,418,111,-261,-265,-33,-35,-36,-8,-6,-166,376,174,292,-224,-220,-165,-278,174,-288,444,312,-148,174,-175,-240,111,111,111,111,111,174,-32,-34,111,-222,-226,-225,-221,-279,-280,-289,-290,111,111,-146,13,174,-147,-254,-256,-257,111,-223,-227,-219,-281,-155,111,-259,111,493,-255,-258,-260,111,]),'$end':([0,1,2,3,4,5,6,7,8,15,22,59,85,92,94,167,177,179,180,197,208,211,213,284,285,325,383,387,434,435,438,439,468,],[-1,0,-2,-3,-266,-267,-272,-273,-274,-286,-115,-271,-269,-270,-242,-275,-282,-283,-287,-268,-243,-244,-246,-276,-277,-245,-278,-288,-279,-280,-289,-290,-281,]),'__ATTRIBUTE__':([0,1,2,3,4,5,6,7,8,11,13,15,17,19,20,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,61,63,66,73,74,75,77,79,80,82,83,84,85,86,88,89,91,92,93,94,96,111,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,166,167,171,172,173,174,175,177,179,180,183,186,188,195,196,197,200,201,202,208,211,213,248,251,252,253,255,256,257,258,263,264,265,269,283,284,285,287,289,290,291,292,294,298,304,305,306,308,309,312,316,317,318,320,321,325,327,328,333,343,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,376,377,378,380,382,383,387,397,398,401,402,403,405,407,409,412,415,421,422,423,424,426,427,429,432,433,434,435,438,439,444,447,448,450,452,453,460,463,465,466,467,468,471,477,478,489,495,502,504,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,-153,-153,-286,76,-189,76,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-151,-152,-153,-271,-247,-153,-153,76,-20,-153,-154,-188,-153,76,-201,-202,-153,-269,76,76,76,-176,-270,-248,-242,-153,-153,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-153,-275,-114,76,-67,-153,-4,-282,-283,-287,76,-193,-196,-203,-204,-268,-149,-153,-150,-243,-244,-246,-153,-37,-38,-55,-56,-57,-58,-153,-23,-24,-25,-26,76,-276,-277,-153,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-153,-161,-153,-174,-245,-5,-7,-30,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,76,-153,76,-153,76,-224,-220,76,-278,-288,76,76,-153,-148,-162,-164,-153,-153,-175,-68,-32,-34,-153,-59,76,-222,-226,-225,-221,-279,-280,-289,-290,-153,-146,-163,76,-153,-147,-98,-43,-223,-227,-219,-281,-155,-153,76,76,-44,-45,-46,]),'TYPEDEF':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,74,75,77,79,84,85,86,88,91,92,93,94,96,167,177,179,180,183,186,188,193,197,200,202,208,211,213,284,285,292,298,304,305,306,308,312,321,325,376,377,383,387,398,402,412,434,435,438,439,447,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,31,-153,-286,31,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,31,-153,-154,-188,-153,-153,-269,31,-119,-176,-270,-248,-242,-153,-275,-282,-283,-287,-118,-193,-196,31,-268,-149,-150,-243,-244,-246,-276,-277,-153,-191,-192,-194,-195,-153,-153,-174,-245,-153,31,-278,-288,31,-148,-175,-279,-280,-289,-290,-146,-147,-281,-155,]),'EXTERN':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,74,75,77,79,84,85,86,88,91,92,93,94,96,167,177,179,180,183,186,188,193,197,200,202,208,211,213,284,285,292,298,304,305,306,308,312,321,325,376,377,383,387,398,402,412,434,435,438,439,447,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,32,-153,-286,32,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,32,-153,-154,-188,-153,-153,-269,32,-119,-176,-270,-248,-242,-153,-275,-282,-283,-287,-118,-193,-196,32,-268,-149,-150,-243,-244,-246,-276,-277,-153,-191,-192,-194,-195,-153,-153,-174,-245,-153,32,-278,-288,32,-148,-175,-279,-280,-289,-290,-146,-147,-281,-155,]),'STATIC':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,74,75,77,79,84,85,86,88,91,92,93,94,96,167,177,179,180,183,186,188,193,197,200,202,208,211,213,284,285,292,298,304,305,306,308,312,321,325,376,377,383,387,398,402,412,434,435,438,439,447,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,33,-153,-286,33,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,33,-153,-154,-188,-153,-153,-269,33,-119,-176,-270,-248,-242,-153,-275,-282,-283,-287,-118,-193,-196,33,-268,-149,-150,-243,-244,-246,-276,-277,-153,-191,-192,-194,-195,-153,-153,-174,-245,-153,33,-278,-288,33,-148,-175,-279,-280,-289,-290,-146,-147,-281,-155,]),'AUTO':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,74,75,77,79,84,85,86,88,91,92,93,94,96,167,177,179,180,183,186,188,193,197,200,202,208,211,213,284,285,292,298,304,305,306,308,312,321,325,376,377,383,387,398,402,412,434,435,438,439,447,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,34,-153,-286,34,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,34,-153,-154,-188,-153,-153,-269,34,-119,-176,-270,-248,-242,-153,-275,-282,-283,-287,-118,-193,-196,34,-268,-149,-150,-243,-244,-246,-276,-277,-153,-191,-192,-194,-195,-153,-153,-174,-245,-153,34,-278,-288,34,-148,-175,-279,-280,-289,-290,-146,-147,-281,-155,]),'REGISTER':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,74,75,77,79,84,85,86,88,91,92,93,94,96,167,177,179,180,183,186,188,193,197,200,202,208,211,213,284,285,292,298,304,305,306,308,312,321,325,376,377,383,387,398,402,412,434,435,438,439,447,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,35,-153,-286,35,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,35,-153,-154,-188,-153,-153,-269,35,-119,-176,-270,-248,-242,-153,-275,-282,-283,-287,-118,-193,-196,35,-268,-149,-150,-243,-244,-246,-276,-277,-153,-191,-192,-194,-195,-153,-153,-174,-245,-153,35,-278,-288,35,-148,-175,-279,-280,-289,-290,-146,-147,-281,-155,]),'VOID':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,36,-153,-286,36,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,36,-153,-153,-154,-188,-153,-153,-269,36,-119,-176,-270,-248,-242,-153,-153,-275,36,36,-153,-282,-283,-287,-118,-193,-196,36,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,36,-153,-174,-245,-166,-153,36,-165,-278,-288,36,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'_BOOL':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,37,-153,-286,37,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,37,-153,-153,-154,-188,-153,-153,-269,37,-119,-176,-270,-248,-242,-153,-153,-275,37,37,-153,-282,-283,-287,-118,-193,-196,37,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,37,-153,-174,-245,-166,-153,37,-165,-278,-288,37,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'CHAR':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,38,-153,-286,38,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,38,-153,-153,-154,-188,-153,-153,-269,38,-119,-176,-270,-248,-242,-153,-153,-275,38,38,-153,-282,-283,-287,-118,-193,-196,38,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,38,-153,-174,-245,-166,-153,38,-165,-278,-288,38,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'SHORT':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,39,-153,-286,39,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,39,-153,-153,-154,-188,-153,-153,-269,39,-119,-176,-270,-248,-242,-153,-153,-275,39,39,-153,-282,-283,-287,-118,-193,-196,39,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,39,-153,-174,-245,-166,-153,39,-165,-278,-288,39,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'INT':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,40,-153,-286,40,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,40,-153,-153,-154,-188,-153,-153,-269,40,-119,-176,-270,-248,-242,-153,-153,-275,40,40,-153,-282,-283,-287,-118,-193,-196,40,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,40,-153,-174,-245,-166,-153,40,-165,-278,-288,40,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'LONG':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,41,-153,-286,41,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,41,-153,-153,-154,-188,-153,-153,-269,41,-119,-176,-270,-248,-242,-153,-153,-275,41,41,-153,-282,-283,-287,-118,-193,-196,41,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,41,-153,-174,-245,-166,-153,41,-165,-278,-288,41,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'FLOAT':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,42,-153,-286,42,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,42,-153,-153,-154,-188,-153,-153,-269,42,-119,-176,-270,-248,-242,-153,-153,-275,42,42,-153,-282,-283,-287,-118,-193,-196,42,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,42,-153,-174,-245,-166,-153,42,-165,-278,-288,42,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'DOUBLE':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,43,-153,-286,43,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,43,-153,-153,-154,-188,-153,-153,-269,43,-119,-176,-270,-248,-242,-153,-153,-275,43,43,-153,-282,-283,-287,-118,-193,-196,43,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,43,-153,-174,-245,-166,-153,43,-165,-278,-288,43,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'SIGNED':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,44,-153,-286,44,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,44,-153,-153,-154,-188,-153,-153,-269,44,-119,-176,-270,-248,-242,-153,-153,-275,44,44,-153,-282,-283,-287,-118,-193,-196,44,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,44,-153,-174,-245,-166,-153,44,-165,-278,-288,44,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'UNSIGNED':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,45,-153,-286,45,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,45,-153,-153,-154,-188,-153,-153,-269,45,-119,-176,-270,-248,-242,-153,-153,-275,45,45,-153,-282,-283,-287,-118,-193,-196,45,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,45,-153,-174,-245,-166,-153,45,-165,-278,-288,45,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'TYPE_NAME':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,61,62,63,74,75,77,79,84,85,86,88,89,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,48,-153,-286,48,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-151,-152,-153,-271,-247,-153,48,-153,-153,-154,-188,-153,-153,-269,48,-119,202,-176,-270,-248,-242,-153,-153,-275,48,48,-153,-282,-283,-287,-118,-193,-196,48,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,48,-153,-174,-245,-166,-153,48,-165,-278,-288,48,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'CONST':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,20,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,80,82,83,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,195,196,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,49,-153,-286,49,-189,49,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,49,-153,-153,-154,-188,-153,49,-201,-202,-153,-269,49,-119,-176,-270,-248,-242,-153,-153,-275,49,49,-153,-282,-283,-287,-118,-193,-196,49,-203,-204,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,49,-153,-174,-245,-166,-153,49,-165,-278,-288,49,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'VOLATILE':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,20,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,80,82,83,84,85,86,88,91,92,93,94,96,111,139,167,170,172,174,177,179,180,183,186,188,193,195,196,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,50,-153,-286,50,-189,50,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,50,-153,-153,-154,-188,-153,50,-201,-202,-153,-269,50,-119,-176,-270,-248,-242,-153,-153,261,-275,50,50,-153,-282,-283,-287,-118,-193,-196,50,-203,-204,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,50,-153,-174,-245,-166,-153,50,-165,-278,-288,50,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'RESTRICT':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,20,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,80,82,83,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,195,196,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,51,-153,-286,51,-189,51,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,51,-153,-153,-154,-188,-153,51,-201,-202,-153,-269,51,-119,-176,-270,-248,-242,-153,-153,-275,51,51,-153,-282,-283,-287,-118,-193,-196,51,-203,-204,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,51,-153,-174,-245,-166,-153,51,-165,-278,-288,51,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'INLINE':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,74,75,77,79,84,85,86,88,91,92,93,94,96,167,177,179,180,183,186,188,193,197,200,202,208,211,213,284,285,292,298,304,305,306,308,312,321,325,376,377,383,387,398,402,412,434,435,438,439,447,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,52,-153,-286,52,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,52,-153,-154,-188,-153,-153,-269,52,-119,-176,-270,-248,-242,-153,-275,-282,-283,-287,-118,-193,-196,52,-268,-149,-150,-243,-244,-246,-276,-277,-153,-191,-192,-194,-195,-153,-153,-174,-245,-153,52,-278,-288,52,-148,-175,-279,-280,-289,-290,-146,-147,-281,-155,]),'_NORETURN':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,74,75,77,79,84,85,86,88,91,92,93,94,96,167,177,179,180,183,186,188,193,197,200,202,208,211,213,284,285,292,298,304,305,306,308,312,321,325,376,377,383,387,398,402,412,434,435,438,439,447,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,53,-153,-286,53,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,53,-153,-154,-188,-153,-153,-269,53,-119,-176,-270,-248,-242,-153,-275,-282,-283,-287,-118,-193,-196,53,-268,-149,-150,-243,-244,-246,-276,-277,-153,-191,-192,-194,-195,-153,-153,-174,-245,-153,53,-278,-288,53,-148,-175,-279,-280,-289,-290,-146,-147,-281,-155,]),'ENUM':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,55,-153,-286,55,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,55,-153,-153,-154,-188,-153,-153,-269,55,-119,-176,-270,-248,-242,-153,-153,-275,55,55,-153,-282,-283,-287,-118,-193,-196,55,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,55,-153,-174,-245,-166,-153,55,-165,-278,-288,55,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'STRUCT':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,56,-153,-286,56,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,56,-153,-153,-154,-188,-153,-153,-269,56,-119,-176,-270,-248,-242,-153,-153,-275,56,56,-153,-282,-283,-287,-118,-193,-196,56,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,56,-153,-174,-245,-166,-153,56,-165,-278,-288,56,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'UNION':([0,1,2,3,4,5,6,7,8,10,11,15,17,19,21,22,23,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,74,75,77,79,84,85,86,88,91,92,93,94,96,111,167,170,172,174,177,179,180,183,186,188,193,197,200,201,202,208,211,213,248,258,284,285,287,290,291,292,294,298,304,305,306,308,312,316,317,318,319,320,321,325,372,376,377,382,383,387,398,401,402,403,405,409,412,423,434,435,438,439,444,447,448,453,468,471,],[-1,-153,-2,-3,-266,-267,-272,-273,-274,57,-153,-286,57,-189,-190,-115,-153,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-153,-271,-247,-153,57,-153,-153,-154,-188,-153,-153,-269,57,-119,-176,-270,-248,-242,-153,-153,-275,57,57,-153,-282,-283,-287,-118,-193,-196,57,-268,-149,-153,-150,-243,-244,-246,-153,-153,-276,-277,-153,-167,-168,-153,-153,-191,-192,-194,-195,-153,-153,-153,-153,-161,57,-153,-174,-245,-166,-153,57,-165,-278,-288,57,-153,-148,-162,-164,-153,-175,-153,-279,-280,-289,-290,-153,-146,-163,-147,-281,-155,]),'SEMI':([9,10,19,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,60,61,62,73,74,75,77,86,88,91,93,94,95,96,97,98,99,100,101,102,103,104,105,106,109,114,117,118,119,120,121,122,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,166,171,173,175,183,186,188,199,200,202,208,209,210,211,212,213,214,215,218,219,227,228,229,230,231,232,251,252,253,255,256,257,263,264,265,269,283,287,290,291,294,298,304,305,306,313,314,319,321,325,326,327,328,329,330,331,333,338,339,340,341,343,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,382,402,404,406,407,412,413,414,415,416,417,421,422,424,445,447,450,452,453,454,455,456,458,460,463,471,474,476,477,478,479,480,481,482,489,490,491,492,495,502,504,],[22,-116,-189,-190,-115,-153,-117,-153,-124,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-247,105,-116,-20,-153,-154,-188,-126,-119,-176,-248,-242,105,105,214,-249,-233,-234,-235,-236,-237,-238,-251,-4,219,105,229,230,231,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-153,-114,-67,-4,-118,-193,-196,-125,-149,-150,-243,-250,214,-244,105,-246,-253,105,105,-252,105,339,-262,-263,-264,340,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-126,-153,-167,-168,-153,-191,-192,-194,-195,-127,-228,405,-174,-245,-239,-5,-7,105,-241,-113,-30,105,-261,-265,-100,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-166,-165,-148,448,-169,-153,-175,-240,105,-68,105,105,-32,-34,-59,-229,-146,-171,-153,-147,-254,-256,-257,105,-98,-43,-155,-230,-170,-153,-172,105,491,-259,105,-173,-255,-258,-260,-44,-45,-46,]),'LBRACE':([11,19,21,22,23,54,55,56,57,58,60,61,75,77,84,89,91,93,94,95,96,98,99,100,101,102,103,104,105,114,186,188,198,200,202,208,209,211,212,213,214,215,218,219,229,230,231,298,304,305,306,315,325,326,329,330,339,340,413,414,416,417,446,454,455,456,458,471,479,481,482,490,491,492,],[61,-189,-190,-115,61,-153,90,-151,-152,61,-247,61,-154,-188,61,201,207,-248,-242,61,61,-249,-233,-234,-235,-236,-237,-238,-251,61,-193,-196,315,316,320,-243,-250,-244,61,-246,-253,61,61,-252,-262,-263,-264,-191,-192,-194,-195,315,-245,-239,61,-241,-261,-265,-240,61,61,61,315,-254,-256,-257,61,-155,61,-259,61,-255,-258,-260,]),'PP_DEFINE_NAME':([12,14,],[63,67,]),'PP_DEFINE_MACRO_NAME':([12,],[64,]),'error':([12,22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,227,229,230,231,325,326,329,330,338,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[65,-115,-247,97,-248,-242,210,210,-249,-233,-234,-235,-236,-237,-238,-251,210,-243,-250,-244,210,-246,-253,210,210,-252,210,-262,-263,-264,-245,-239,210,-241,210,-261,-265,-240,210,210,210,-254,-256,-257,210,210,-259,210,-255,-258,-260,]),'PRAGMA_PACK':([16,],[69,]),'STRING_LITERAL':([16,22,60,61,63,68,70,71,72,73,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,140,144,146,158,174,181,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,263,264,265,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,353,375,385,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,464,479,481,482,490,491,492,493,494,496,501,],[73,-115,-247,73,73,73,-296,-298,-299,-20,73,-248,-242,73,73,-249,-233,-234,-235,-236,-237,-238,-251,73,73,73,73,73,73,73,73,-61,-62,-63,-64,-65,-66,-21,73,-25,-22,73,-297,73,-243,-250,-244,73,-246,-253,73,73,-252,73,73,73,73,73,-262,-263,-264,73,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,73,73,73,73,73,73,73,73,-23,-24,-25,73,73,-26,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,-245,-239,73,-241,73,73,-261,-265,73,73,73,73,-240,73,73,73,73,73,73,73,73,73,73,-254,-256,-257,73,73,73,-259,73,-255,-258,-260,73,73,73,73,]),'EQUALS':([19,21,23,73,75,77,86,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,166,173,175,186,188,206,251,252,253,255,256,257,263,264,265,269,283,298,304,305,306,327,328,333,345,349,350,356,357,415,421,422,424,463,471,495,502,504,],[-189,-190,-153,-20,-154,-188,198,-4,234,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-153,-67,-4,-193,-196,323,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,198,-191,-192,-194,-195,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-155,-44,-45,-46,]),'COMMA':([19,20,21,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,73,74,75,77,80,81,82,83,86,88,91,106,109,120,121,122,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,166,170,171,173,175,183,186,188,189,190,191,192,193,194,195,196,199,200,202,204,205,206,222,232,251,252,253,255,256,257,263,264,265,269,283,286,287,288,289,290,291,294,296,297,298,302,303,304,305,306,309,310,311,313,314,321,327,328,331,332,333,335,336,341,342,343,344,345,346,347,348,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,378,380,382,391,392,393,394,396,397,399,400,402,404,406,407,410,411,412,415,421,422,424,426,427,429,432,433,437,440,441,443,445,447,450,452,453,457,459,460,461,462,463,464,465,466,467,471,472,473,474,475,476,477,478,483,484,485,488,489,494,495,497,498,499,500,501,502,503,504,],[-189,-197,-190,-153,87,-153,-124,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-20,-153,-154,-188,-198,-199,-201,-202,-126,-119,-176,-4,220,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-153,-214,-114,-67,-4,-118,-193,-196,307,308,-212,-207,-211,-200,-203,-204,-125,-149,-150,322,-179,-181,220,220,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-126,-215,-153,-216,-153,-167,-168,-153,386,-284,-191,390,-158,-192,-194,-195,-153,-210,-216,-127,-228,-174,-5,-7,-113,220,-30,220,220,-100,220,-96,220,-33,423,-39,-41,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-166,-153,-217,-224,-220,-165,443,-156,-159,-213,-208,-209,446,-231,-148,449,-169,-153,-180,-182,-175,-68,-32,-34,-59,-218,-222,-226,-225,-221,-285,469,470,-158,-229,-146,-171,-153,-147,220,220,-98,-40,-42,-43,-47,-223,-227,-219,-155,-157,423,-230,-232,-170,-153,-172,-50,496,-48,-160,-173,-47,-44,220,496,-49,-51,-47,-45,496,-46,]),'RPAREN':([19,20,21,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,73,74,75,77,79,80,81,82,83,88,91,105,120,121,122,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,170,173,175,176,178,182,183,186,187,188,189,190,191,192,193,194,195,196,200,202,214,219,222,223,248,251,252,253,255,256,257,263,264,265,269,286,287,288,289,290,291,292,294,296,297,298,300,301,302,303,304,305,306,309,310,311,312,321,327,328,331,332,333,335,336,341,343,345,346,347,348,349,350,351,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,376,378,379,380,382,391,392,393,394,395,396,397,402,412,415,419,421,422,424,425,426,427,429,430,431,432,433,437,440,441,442,443,447,453,457,459,460,461,462,463,464,465,466,467,471,472,473,483,484,485,486,487,488,494,495,497,498,499,500,501,502,503,504,],[-189,-197,-190,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-20,-153,-154,-188,188,-198,-199,-201,-202,-119,-176,-251,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-214,-67,-4,295,298,299,-118,-193,305,-196,306,-205,-212,-207,-211,-200,-203,-204,-149,-150,-253,-252,333,334,345,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-215,-153,-216,-153,-167,-168,378,-153,385,-284,-191,388,389,-291,-158,-192,-194,-195,-153,-210,-216,378,-174,-5,-7,-113,414,-30,416,417,-100,-96,-33,422,-39,-41,-35,-36,424,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-166,-153,-217,429,-224,432,-220,-165,442,-156,-159,-213,-206,-208,-209,-148,-175,-68,458,-32,-34,-59,463,-218,-222,-226,466,467,-225,-221,-285,-292,-295,471,-158,-146,-147,480,482,-98,-40,-42,-43,-47,-223,-227,-219,-155,-157,488,-50,495,-48,-293,-294,-160,-47,-44,500,502,-49,-51,-47,-45,504,-46,]),'COLON':([19,21,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,73,75,77,91,106,108,120,121,122,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,171,173,175,186,188,200,202,217,251,252,253,255,256,257,263,264,265,269,287,290,291,294,298,304,305,306,319,321,327,328,331,333,341,342,343,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,382,402,407,412,415,421,422,424,425,447,449,453,460,463,464,471,483,484,485,494,495,498,499,500,502,504,],[-189,-190,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-20,-154,-188,-176,215,218,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-114,-67,-4,-193,-196,-149,-150,329,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-153,-167,-168,-153,-191,-192,-194,-195,408,-174,-5,-7,-113,-30,-100,420,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-166,-165,-148,451,-175,-68,-32,-34,-59,464,-146,408,-147,-98,-43,-47,-155,-50,494,-48,-47,-44,501,-49,-51,-45,-46,]),'LBRACKET':([19,20,21,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,73,74,75,77,80,81,82,83,88,91,106,124,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,170,175,183,186,188,193,194,195,196,200,202,251,252,263,264,265,269,287,288,289,290,291,292,294,298,304,305,306,311,312,321,327,328,333,345,349,350,356,357,372,373,377,378,380,382,398,402,412,421,422,427,429,432,433,447,453,465,466,467,471,],[78,-197,-190,-153,-120,-121,-122,-123,-128,-129,-130,-131,-132,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,-186,-187,-20,-153,-154,78,-198,-199,-201,-202,-119,-176,-4,247,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,293,-4,-118,-193,-196,293,-200,-203,-204,-149,-150,-37,-38,-23,-24,-25,-26,-153,293,375,-167,-168,-153,-153,-191,-192,-194,-195,293,-153,-174,-5,-7,-30,-33,-35,-36,-8,-6,-166,375,293,-224,-220,-165,293,-148,-175,-32,-34,-222,-226,-225,-221,-146,-147,-223,-227,-219,-155,]),'PP_END_DEFINE':([20,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,63,65,67,73,75,80,81,82,83,91,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,168,169,170,171,173,175,194,195,196,200,202,251,252,253,255,256,257,263,264,265,269,286,287,288,289,290,291,294,295,321,327,328,333,343,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,378,380,382,384,385,402,412,415,421,422,424,426,427,429,432,433,436,447,453,460,463,465,466,467,471,495,502,504,],[-197,-133,-134,-135,-136,-137,-138,-139,-140,-141,-142,-143,-144,-145,-183,-184,-185,167,177,179,-20,-154,-198,-199,-201,-202,-176,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,284,285,-214,-114,-67,-4,-200,-203,-204,-149,-150,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-215,-153,-216,-153,-167,-168,-153,383,-174,-5,-7,-30,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-166,-153,-217,-224,-220,-165,434,435,-148,-175,-68,-32,-34,-59,-218,-222,-226,-225,-221,468,-146,-147,-98,-43,-223,-227,-219,-155,-44,-45,-46,]),'RBRACE':([22,60,61,73,93,94,95,96,97,98,99,100,101,102,103,104,105,121,122,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,171,173,175,203,204,205,206,208,209,211,212,213,214,219,229,230,231,251,252,253,255,256,257,263,264,265,269,314,317,318,322,324,325,326,327,328,330,333,339,340,341,343,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,399,400,401,403,405,409,410,411,413,415,421,422,424,445,446,448,454,455,456,460,463,474,475,481,490,491,492,495,502,504,],[-115,-247,94,-20,-248,-242,208,211,213,-249,-233,-234,-235,-236,-237,-238,-251,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-114,-67,-4,321,-177,-179,-181,-243,-250,-244,325,-246,-253,-252,-262,-263,-264,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-228,402,-161,-178,412,-245,-239,-5,-7,-241,-30,-261,-265,-100,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,445,-231,447,-162,-164,453,-180,-182,-240,-68,-32,-34,-59,-229,474,-163,-254,-256,-257,-98,-43,-230,-232,-259,-255,-258,-260,-44,-45,-46,]),'CASE':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,107,-248,-242,107,107,-249,-233,-234,-235,-236,-237,-238,-251,107,-243,-250,-244,107,-246,-253,107,107,-252,-262,-263,-264,-245,-239,107,-241,-261,-265,-240,107,107,107,-254,-256,-257,107,107,-259,107,-255,-258,-260,]),'DEFAULT':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,108,-248,-242,108,108,-249,-233,-234,-235,-236,-237,-238,-251,108,-243,-250,-244,108,-246,-253,108,108,-252,-262,-263,-264,-245,-239,108,-241,-261,-265,-240,108,108,108,-254,-256,-257,108,108,-259,108,-255,-258,-260,]),'IF':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,110,-248,-242,110,110,-249,-233,-234,-235,-236,-237,-238,-251,110,-243,-250,-244,110,-246,-253,110,110,-252,-262,-263,-264,-245,-239,110,-241,-261,-265,-240,110,110,110,-254,-256,-257,110,110,-259,110,-255,-258,-260,]),'SWITCH':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,112,-248,-242,112,112,-249,-233,-234,-235,-236,-237,-238,-251,112,-243,-250,-244,112,-246,-253,112,112,-252,-262,-263,-264,-245,-239,112,-241,-261,-265,-240,112,112,112,-254,-256,-257,112,112,-259,112,-255,-258,-260,]),'WHILE':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,226,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,113,-248,-242,113,113,-249,-233,-234,-235,-236,-237,-238,-251,113,-243,-250,-244,113,-246,-253,113,113,-252,337,-262,-263,-264,-245,-239,113,-241,-261,-265,-240,113,113,113,-254,-256,-257,113,113,-259,113,-255,-258,-260,]),'DO':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,114,-248,-242,114,114,-249,-233,-234,-235,-236,-237,-238,-251,114,-243,-250,-244,114,-246,-253,114,114,-252,-262,-263,-264,-245,-239,114,-241,-261,-265,-240,114,114,114,-254,-256,-257,114,114,-259,114,-255,-258,-260,]),'FOR':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,115,-248,-242,115,115,-249,-233,-234,-235,-236,-237,-238,-251,115,-243,-250,-244,115,-246,-253,115,115,-252,-262,-263,-264,-245,-239,115,-241,-261,-265,-240,115,115,115,-254,-256,-257,115,115,-259,115,-255,-258,-260,]),'GOTO':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,116,-248,-242,116,116,-249,-233,-234,-235,-236,-237,-238,-251,116,-243,-250,-244,116,-246,-253,116,116,-252,-262,-263,-264,-245,-239,116,-241,-261,-265,-240,116,116,116,-254,-256,-257,116,116,-259,116,-255,-258,-260,]),'CONTINUE':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,117,-248,-242,117,117,-249,-233,-234,-235,-236,-237,-238,-251,117,-243,-250,-244,117,-246,-253,117,117,-252,-262,-263,-264,-245,-239,117,-241,-261,-265,-240,117,117,117,-254,-256,-257,117,117,-259,117,-255,-258,-260,]),'BREAK':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,118,-248,-242,118,118,-249,-233,-234,-235,-236,-237,-238,-251,118,-243,-250,-244,118,-246,-253,118,118,-252,-262,-263,-264,-245,-239,118,-241,-261,-265,-240,118,118,118,-254,-256,-257,118,118,-259,118,-255,-258,-260,]),'RETURN':([22,60,61,93,94,95,96,98,99,100,101,102,103,104,105,114,208,209,211,212,213,214,215,218,219,229,230,231,325,326,329,330,339,340,413,414,416,417,454,455,456,458,479,481,482,490,491,492,],[-115,-247,119,-248,-242,119,119,-249,-233,-234,-235,-236,-237,-238,-251,119,-243,-250,-244,119,-246,-253,119,119,-252,-262,-263,-264,-245,-239,119,-241,-261,-265,-240,119,119,119,-254,-256,-257,119,119,-259,119,-255,-258,-260,]),'INC_OP':([22,60,61,63,73,78,93,94,95,96,98,99,100,101,102,103,104,105,106,107,111,114,119,124,125,126,127,129,132,133,134,135,136,137,138,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,174,175,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,251,252,254,258,259,262,263,264,265,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,327,328,329,330,333,334,338,339,340,345,349,350,356,357,375,385,408,413,414,416,417,418,419,420,421,422,423,444,446,451,454,455,456,458,479,481,482,490,491,492,493,],[-115,-247,125,125,-20,125,-248,-242,125,125,-249,-233,-234,-235,-236,-237,-238,-251,-4,125,125,125,125,251,125,125,125,125,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,125,-4,125,-243,-250,-244,125,-246,-253,125,125,-252,125,125,125,125,125,-262,-263,-264,125,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,125,125,125,125,-37,-38,125,125,125,125,-23,-24,-25,125,125,-26,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-245,-239,-5,-7,125,-241,-30,125,125,-261,-265,-33,-35,-36,-8,-6,125,125,125,-240,125,125,125,125,125,125,-32,-34,125,125,125,125,-254,-256,-257,125,125,-259,125,-255,-258,-260,125,]),'DEC_OP':([22,60,61,63,73,78,93,94,95,96,98,99,100,101,102,103,104,105,106,107,111,114,119,124,125,126,127,129,132,133,134,135,136,137,138,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,174,175,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,251,252,254,258,259,262,263,264,265,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,327,328,329,330,333,334,338,339,340,345,349,350,356,357,375,385,408,413,414,416,417,418,419,420,421,422,423,444,446,451,454,455,456,458,479,481,482,490,491,492,493,],[-115,-247,126,126,-20,126,-248,-242,126,126,-249,-233,-234,-235,-236,-237,-238,-251,-4,126,126,126,126,252,126,126,126,126,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,126,-4,126,-243,-250,-244,126,-246,-253,126,126,-252,126,126,126,126,126,-262,-263,-264,126,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,126,126,126,126,-37,-38,126,126,126,126,-23,-24,-25,126,126,-26,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,-245,-239,-5,-7,126,-241,-30,126,126,-261,-265,-33,-35,-36,-8,-6,126,126,126,-240,126,126,126,126,126,126,-32,-34,126,126,126,126,-254,-256,-257,126,126,-259,126,-255,-258,-260,126,]),'SIZEOF':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,479,481,482,490,491,492,493,],[-115,-247,129,129,129,-248,-242,129,129,-249,-233,-234,-235,-236,-237,-238,-251,129,129,129,129,129,129,129,129,-61,-62,-63,-64,-65,-66,129,129,-243,-250,-244,129,-246,-253,129,129,-252,129,129,129,129,129,-262,-263,-264,129,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,-245,-239,129,-241,129,129,-261,-265,129,129,129,-240,129,129,129,129,129,129,129,129,129,129,-254,-256,-257,129,129,-259,129,-255,-258,-260,129,]),'AND':([22,60,61,63,73,78,93,94,95,96,98,99,100,101,102,103,104,105,106,107,111,114,119,122,124,125,126,127,128,129,130,132,133,134,135,136,137,138,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,173,174,175,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,251,252,253,254,255,256,257,258,259,262,263,264,265,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,327,328,329,330,333,334,338,339,340,345,349,350,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,375,385,408,413,414,415,416,417,418,419,420,421,422,423,424,444,446,451,454,455,456,458,463,479,481,482,490,491,492,493,495,502,504,],[-115,-247,133,133,-20,133,-248,-242,133,133,-249,-233,-234,-235,-236,-237,-238,-251,-4,133,133,133,133,-67,-54,133,133,133,-69,133,-60,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,268,-87,-84,-79,-76,-73,-67,133,-4,133,-243,-250,-244,133,-246,-253,133,133,-252,133,133,133,133,133,-262,-263,-264,133,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,133,133,133,133,-37,-38,-55,133,-56,-57,-58,133,133,133,-23,-24,-25,133,133,-26,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,-245,-239,-5,-7,133,-241,-30,133,133,-261,-265,-33,-35,-36,268,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,133,133,133,-240,133,-68,133,133,133,133,133,-32,-34,133,-59,133,133,133,-254,-256,-257,133,-43,133,-259,133,-255,-258,-260,133,-44,-45,-46,]),'PLUS':([22,60,61,63,73,78,93,94,95,96,98,99,100,101,102,103,104,105,106,107,111,114,119,122,124,125,126,127,128,129,130,132,133,134,135,136,137,138,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,164,165,173,174,175,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,251,252,253,254,255,256,257,258,259,262,263,264,265,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,327,328,329,330,333,334,338,339,340,345,349,350,356,357,365,366,367,368,369,370,371,375,385,408,413,414,415,416,417,418,419,420,421,422,423,424,444,446,451,454,455,456,458,463,479,481,482,490,491,492,493,495,502,504,],[-115,-247,135,135,-20,135,-248,-242,135,135,-249,-233,-234,-235,-236,-237,-238,-251,-4,135,135,135,135,-67,-54,135,135,135,-69,135,-60,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,278,-73,-67,135,-4,135,-243,-250,-244,135,-246,-253,135,135,-252,135,135,135,135,135,-262,-263,-264,135,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,135,135,135,135,-37,-38,-55,135,-56,-57,-58,135,135,135,-23,-24,-25,135,135,-26,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,-245,-239,-5,-7,135,-241,-30,135,135,-261,-265,-33,-35,-36,-8,-6,278,278,-74,-75,-70,-71,-72,135,135,135,-240,135,-68,135,135,135,135,135,-32,-34,135,-59,135,135,135,-254,-256,-257,135,-43,135,-259,135,-255,-258,-260,135,-44,-45,-46,]),'MINUS':([22,60,61,63,73,78,93,94,95,96,98,99,100,101,102,103,104,105,106,107,111,114,119,122,124,125,126,127,128,129,130,132,133,134,135,136,137,138,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,164,165,173,174,175,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,251,252,253,254,255,256,257,258,259,262,263,264,265,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,327,328,329,330,333,334,338,339,340,345,349,350,356,357,365,366,367,368,369,370,371,375,385,408,413,414,415,416,417,418,419,420,421,422,423,424,444,446,451,454,455,456,458,463,479,481,482,490,491,492,493,495,502,504,],[-115,-247,136,136,-20,136,-248,-242,136,136,-249,-233,-234,-235,-236,-237,-238,-251,-4,136,136,136,136,-67,-54,136,136,136,-69,136,-60,-31,-61,-62,-63,-64,-65,-66,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,279,-73,-67,136,-4,136,-243,-250,-244,136,-246,-253,136,136,-252,136,136,136,136,136,-262,-263,-264,136,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,136,136,136,136,-37,-38,-55,136,-56,-57,-58,136,136,136,-23,-24,-25,136,136,-26,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,-245,-239,-5,-7,136,-241,-30,136,136,-261,-265,-33,-35,-36,-8,-6,279,279,-74,-75,-70,-71,-72,136,136,136,-240,136,-68,136,136,136,136,136,-32,-34,136,-59,136,136,136,-254,-256,-257,136,-43,136,-259,136,-255,-258,-260,136,-44,-45,-46,]),'NOT':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,479,481,482,490,491,492,493,],[-115,-247,137,137,137,-248,-242,137,137,-249,-233,-234,-235,-236,-237,-238,-251,137,137,137,137,137,137,137,137,-61,-62,-63,-64,-65,-66,137,137,-243,-250,-244,137,-246,-253,137,137,-252,137,137,137,137,137,-262,-263,-264,137,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,-245,-239,137,-241,137,137,-261,-265,137,137,137,-240,137,137,137,137,137,137,137,137,137,137,-254,-256,-257,137,137,-259,137,-255,-258,-260,137,]),'LNOT':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,479,481,482,490,491,492,493,],[-115,-247,138,138,138,-248,-242,138,138,-249,-233,-234,-235,-236,-237,-238,-251,138,138,138,138,138,138,138,138,-61,-62,-63,-64,-65,-66,138,138,-243,-250,-244,138,-246,-253,138,138,-252,138,138,138,138,138,-262,-263,-264,138,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,-245,-239,138,-241,138,138,-261,-265,138,138,138,-240,138,138,138,138,138,138,138,138,138,138,-254,-256,-257,138,138,-259,138,-255,-258,-260,138,]),'__ASM__':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,479,481,482,490,491,492,493,],[-115,-247,139,139,139,-248,-242,139,139,-249,-233,-234,-235,-236,-237,-238,-251,139,139,139,139,139,139,139,139,-61,-62,-63,-64,-65,-66,139,139,-243,-250,-244,139,-246,-253,139,139,-252,139,139,139,139,139,-262,-263,-264,139,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,-245,-239,139,-241,139,139,-261,-265,139,139,139,-240,139,139,139,139,139,139,139,139,139,139,-254,-256,-257,139,139,-259,139,-255,-258,-260,139,]),'PP_MACRO_PARAM':([22,60,61,63,73,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,140,144,146,158,160,174,176,198,208,209,211,212,213,214,215,216,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,386,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,479,481,482,490,491,492,493,],[-115,-247,146,146,-20,146,-248,-242,146,146,-249,-233,-234,-235,-236,-237,-238,-251,146,146,146,146,146,146,146,146,-61,-62,-63,-64,-65,-66,-21,265,-25,-22,269,146,297,146,-243,-250,-244,146,-246,-253,146,328,146,-252,146,146,146,146,146,-262,-263,-264,146,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,146,146,146,146,146,146,146,146,-23,-24,-25,146,356,146,-26,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,-245,-239,146,-241,146,146,-261,-265,146,146,437,146,-240,146,146,146,146,146,146,146,146,146,146,-254,-256,-257,146,146,-259,146,-255,-258,-260,146,]),'I_CONST_HEX':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,147,147,147,-248,-242,147,147,-249,-233,-234,-235,-236,-237,-238,-251,147,147,147,147,147,147,147,147,-61,-62,-63,-64,-65,-66,147,147,147,-243,-250,-244,147,-246,-253,147,147,-252,147,147,147,147,147,-262,-263,-264,147,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,-245,-239,147,-241,147,147,-261,-265,147,147,147,147,-240,147,147,147,147,147,147,147,147,147,147,-254,-256,-257,147,147,147,-259,147,-255,-258,-260,147,]),'I_CONST_DEC':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,148,148,148,-248,-242,148,148,-249,-233,-234,-235,-236,-237,-238,-251,148,148,148,148,148,148,148,148,-61,-62,-63,-64,-65,-66,148,148,148,-243,-250,-244,148,-246,-253,148,148,-252,148,148,148,148,148,-262,-263,-264,148,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,-245,-239,148,-241,148,148,-261,-265,148,148,148,148,-240,148,148,148,148,148,148,148,148,148,148,-254,-256,-257,148,148,148,-259,148,-255,-258,-260,148,]),'I_CONST_OCT':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,149,149,149,-248,-242,149,149,-249,-233,-234,-235,-236,-237,-238,-251,149,149,149,149,149,149,149,149,-61,-62,-63,-64,-65,-66,149,149,149,-243,-250,-244,149,-246,-253,149,149,-252,149,149,149,149,149,-262,-263,-264,149,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,-245,-239,149,-241,149,149,-261,-265,149,149,149,149,-240,149,149,149,149,149,149,149,149,149,149,-254,-256,-257,149,149,149,-259,149,-255,-258,-260,149,]),'I_CONST_BIN':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,150,150,150,-248,-242,150,150,-249,-233,-234,-235,-236,-237,-238,-251,150,150,150,150,150,150,150,150,-61,-62,-63,-64,-65,-66,150,150,150,-243,-250,-244,150,-246,-253,150,150,-252,150,150,150,150,150,-262,-263,-264,150,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,-245,-239,150,-241,150,150,-261,-265,150,150,150,150,-240,150,150,150,150,150,150,150,150,150,150,-254,-256,-257,150,150,150,-259,150,-255,-258,-260,150,]),'F_CONST_1':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,151,151,151,-248,-242,151,151,-249,-233,-234,-235,-236,-237,-238,-251,151,151,151,151,151,151,151,151,-61,-62,-63,-64,-65,-66,151,151,151,-243,-250,-244,151,-246,-253,151,151,-252,151,151,151,151,151,-262,-263,-264,151,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,-245,-239,151,-241,151,151,-261,-265,151,151,151,151,-240,151,151,151,151,151,151,151,151,151,151,-254,-256,-257,151,151,151,-259,151,-255,-258,-260,151,]),'F_CONST_2':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,152,152,152,-248,-242,152,152,-249,-233,-234,-235,-236,-237,-238,-251,152,152,152,152,152,152,152,152,-61,-62,-63,-64,-65,-66,152,152,152,-243,-250,-244,152,-246,-253,152,152,-252,152,152,152,152,152,-262,-263,-264,152,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,-245,-239,152,-241,152,152,-261,-265,152,152,152,152,-240,152,152,152,152,152,152,152,152,152,152,-254,-256,-257,152,152,152,-259,152,-255,-258,-260,152,]),'F_CONST_3':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,153,153,153,-248,-242,153,153,-249,-233,-234,-235,-236,-237,-238,-251,153,153,153,153,153,153,153,153,-61,-62,-63,-64,-65,-66,153,153,153,-243,-250,-244,153,-246,-253,153,153,-252,153,153,153,153,153,-262,-263,-264,153,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,-245,-239,153,-241,153,153,-261,-265,153,153,153,153,-240,153,153,153,153,153,153,153,153,153,153,-254,-256,-257,153,153,153,-259,153,-255,-258,-260,153,]),'F_CONST_4':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,154,154,154,-248,-242,154,154,-249,-233,-234,-235,-236,-237,-238,-251,154,154,154,154,154,154,154,154,-61,-62,-63,-64,-65,-66,154,154,154,-243,-250,-244,154,-246,-253,154,154,-252,154,154,154,154,154,-262,-263,-264,154,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,-245,-239,154,-241,154,154,-261,-265,154,154,154,154,-240,154,154,154,154,154,154,154,154,154,154,-254,-256,-257,154,154,154,-259,154,-255,-258,-260,154,]),'F_CONST_5':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,155,155,155,-248,-242,155,155,-249,-233,-234,-235,-236,-237,-238,-251,155,155,155,155,155,155,155,155,-61,-62,-63,-64,-65,-66,155,155,155,-243,-250,-244,155,-246,-253,155,155,-252,155,155,155,155,155,-262,-263,-264,155,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,-245,-239,155,-241,155,155,-261,-265,155,155,155,155,-240,155,155,155,155,155,155,155,155,155,155,-254,-256,-257,155,155,155,-259,155,-255,-258,-260,155,]),'F_CONST_6':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,156,156,156,-248,-242,156,156,-249,-233,-234,-235,-236,-237,-238,-251,156,156,156,156,156,156,156,156,-61,-62,-63,-64,-65,-66,156,156,156,-243,-250,-244,156,-246,-253,156,156,-252,156,156,156,156,156,-262,-263,-264,156,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,-245,-239,156,-241,156,156,-261,-265,156,156,156,156,-240,156,156,156,156,156,156,156,156,156,156,-254,-256,-257,156,156,156,-259,156,-255,-258,-260,156,]),'CHARACTER_CONSTANT':([22,60,61,63,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,174,182,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,390,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,469,479,481,482,490,491,492,493,],[-115,-247,157,157,157,-248,-242,157,157,-249,-233,-234,-235,-236,-237,-238,-251,157,157,157,157,157,157,157,157,-61,-62,-63,-64,-65,-66,157,157,157,-243,-250,-244,157,-246,-253,157,157,-252,157,157,157,157,157,-262,-263,-264,157,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,-245,-239,157,-241,157,157,-261,-265,157,157,157,157,-240,157,157,157,157,157,157,157,157,157,157,-254,-256,-257,157,157,157,-259,157,-255,-258,-260,157,]),'PP_STRINGIFY':([22,60,61,63,73,78,93,94,95,96,98,99,100,101,102,103,104,105,107,111,114,119,125,126,127,129,133,134,135,136,137,138,140,144,146,158,174,198,208,209,211,212,213,214,215,218,219,220,221,224,225,227,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,254,258,259,262,263,264,265,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,325,326,329,330,334,338,339,340,375,385,408,413,414,416,417,418,419,420,423,444,446,451,454,455,456,458,479,481,482,490,491,492,493,],[-115,-247,160,160,-20,160,-248,-242,160,160,-249,-233,-234,-235,-236,-237,-238,-251,160,160,160,160,160,160,160,160,-61,-62,-63,-64,-65,-66,-21,160,-25,-22,160,160,-243,-250,-244,160,-246,-253,160,160,-252,160,160,160,160,160,-262,-263,-264,160,-101,-102,-103,-104,-105,-106,-107,-108,-109,-110,-111,160,160,160,160,160,160,160,160,-23,-24,-25,160,160,-26,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,-245,-239,160,-241,160,160,-261,-265,160,160,160,-240,160,160,160,160,160,160,160,160,160,160,-254,-256,-257,160,160,-259,160,-255,-258,-260,160,]),'PRAGMA_END':([68,70,71,72,73,181,299,388,389,],[180,-296,-298,-299,-20,-297,387,438,439,]),'PERIOD':([73,106,124,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,175,251,252,263,264,265,269,327,328,333,345,349,350,356,357,421,422,],[-20,-4,249,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-4,-37,-38,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-32,-34,]),'PTR_OP':([73,106,124,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,175,251,252,263,264,265,269,327,328,333,345,349,350,356,357,421,422,],[-20,-4,250,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-4,-37,-38,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-32,-34,]),'MUL_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,235,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'DIV_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,236,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'MOD_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,237,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'ADD_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,238,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'SUB_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,239,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'LEFT_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,240,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'RIGHT_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,241,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'AND_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,242,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'XOR_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,243,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'OR_ASSIGN':([73,106,122,124,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,415,421,422,424,463,495,502,504,],[-20,-4,244,-54,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,-68,-32,-34,-59,-43,-44,-45,-46,]),'DIVIDE':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,281,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,281,281,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'MOD':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,282,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,282,282,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'LEFT_OP':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,276,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,276,276,276,276,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'RIGHT_OP':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,277,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,277,277,277,277,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'LT':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,272,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,272,272,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'GT':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,273,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,273,273,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'LE_OP':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,274,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,274,274,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'GE_OP':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,275,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,275,275,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'EQ_OP':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,161,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,270,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,270,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'NE_OP':([73,106,122,124,128,130,132,140,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,161,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,271,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,-8,-6,271,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'XOR':([73,106,122,124,128,130,132,140,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,-27,-28,-29,266,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,266,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'OR':([73,106,122,124,128,130,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,-31,-21,262,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-33,-35,-36,262,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'AND_OP':([73,106,122,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,343,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,-54,-69,-60,259,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,259,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'CONDOP':([73,106,122,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,343,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,245,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'OR_OP':([73,106,122,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,173,175,251,252,253,255,256,257,263,264,265,269,327,328,333,343,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,415,421,422,424,463,495,502,504,],[-20,-4,-67,246,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-67,-4,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,-5,-7,-30,-96,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,-68,-32,-34,-59,-43,-44,-45,-46,]),'RBRACKET':([73,78,120,121,122,123,124,128,130,131,132,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,164,165,171,173,175,185,251,252,253,255,256,257,263,264,265,269,293,327,328,331,333,341,343,344,345,349,350,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,375,381,415,421,422,424,428,460,463,495,502,504,],[-20,186,-112,-99,-67,-97,-54,-69,-60,-95,-31,-21,-93,-27,-28,-29,-91,-25,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-22,-89,-87,-84,-79,-76,-73,-114,-67,-4,304,-37,-38,-55,-56,-57,-58,-23,-24,-25,-26,380,-5,-7,-113,-30,-100,-96,421,-33,-35,-36,-94,-92,-90,-8,-6,-88,-85,-86,-80,-81,-82,-83,-77,-78,-74,-75,-70,-71,-72,427,433,-68,-32,-34,-59,465,-98,-43,-44,-45,-46,]),'ELSE':([94,99,100,101,102,103,104,105,208,211,213,214,219,229,230,231,325,326,330,339,340,413,454,455,456,481,490,491,492,],[-242,-233,-234,-235,-236,-237,-238,-251,-243,-244,-246,-253,-252,-262,-263,-264,-245,-239,-241,-261,-265,-240,479,-256,-257,-259,-255,-258,-260,]),'PP_IDENTIFIER_PASTE':([106,146,175,328,356,],[216,267,216,267,267,]),'ELLIPSIS':([308,],[395,]),} _lr_action = {} for _k, _v in _lr_action_items.items(): @@ -17,7 +17,7 @@ _lr_action[_x][_k] = _y del _lr_action_items -_lr_goto_items = {'translation_unit':([0,],[1,]),'external_declaration':([1,],[2,]),'directive':([1,],[3,]),'declaration':([1,11,23,55,58,76,88,],[4,57,57,85,57,85,85,]),'function_definition':([1,],[5,]),'define':([1,],[6,]),'undefine':([1,],[7,]),'pragma':([1,],[8,]),'declaration_impl':([1,11,23,55,58,76,88,],[9,9,9,9,9,9,9,]),'declaration_specifier_list':([1,11,23,55,58,70,76,88,283,295,299,367,],[10,59,59,59,59,183,59,59,183,183,183,183,]),'declarator':([1,10,59,63,79,183,310,385,440,],[11,23,159,171,159,296,398,171,398,]),'pragma_pack':([1,],[15,]),'gcc_attributes':([1,11,13,23,25,51,55,58,60,65,70,76,88,103,159,167,192,239,249,278,280,283,285,295,296,299,307,308,311,364,367,392,398,400,414,431,443,468,],[16,16,63,78,80,81,16,16,165,173,16,16,16,165,274,165,165,165,165,363,365,368,373,16,384,385,165,165,165,417,16,165,441,165,165,165,469,480,]),'pointer':([1,10,20,59,63,72,79,163,183,310,368,385,440,],[17,17,73,17,17,185,17,279,298,17,279,298,17,]),'direct_declarator':([1,10,17,59,63,79,183,298,310,385,440,],[18,18,68,18,18,18,18,68,18,18,18,]),'init_declarator_list':([10,59,],[24,24,]),'declaration_specifier':([10,16,59,78,183,368,385,],[25,65,25,65,25,65,65,]),'init_declarator':([10,59,79,],[26,26,190,]),'storage_class_specifier':([10,16,59,78,183,368,385,],[27,27,27,27,27,27,27,]),'type_specifier':([10,16,59,78,163,165,183,310,368,385,],[28,28,28,28,281,281,28,281,28,28,]),'type_qualifier':([10,16,20,59,72,78,163,165,183,310,368,385,],[29,29,74,29,186,29,282,282,29,282,29,29,]),'struct_or_union_specifier':([10,16,59,78,163,165,183,310,368,385,],[45,45,45,45,45,45,45,45,45,45,]),'enum_specifier':([10,16,59,78,163,165,183,310,368,385,],[46,46,46,46,46,46,46,46,46,46,]),'struct_or_union':([10,16,59,78,163,165,183,310,368,385,],[51,51,51,51,51,51,51,51,51,51,]),'declaration_list':([11,23,58,],[55,76,88,]),'compound_statement':([11,23,55,58,76,87,88,106,203,206,209,320,405,407,408,449,470,473,],[56,77,84,92,188,92,92,92,92,92,92,92,92,92,92,92,92,92,]),'gcc_attribute':([16,20,63,72,78,80,81,165,173,274,363,365,368,373,384,385,417,441,469,480,],[66,75,66,187,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,]),'type_qualifier_list':([20,],[72,]),'statement_list':([58,88,],[87,203,]),'statement':([58,87,88,106,203,206,209,320,405,407,408,449,470,473,],[90,200,90,217,200,317,321,404,445,446,447,472,481,483,]),'labeled_statement':([58,87,88,106,203,206,209,320,405,407,408,449,470,473,],[91,91,91,91,91,91,91,91,91,91,91,91,91,91,]),'expression_statement':([58,87,88,106,203,206,209,218,320,329,405,407,408,449,470,473,],[93,93,93,93,93,93,93,329,93,410,93,93,93,93,93,93,]),'selection_statement':([58,87,88,106,203,206,209,320,405,407,408,449,470,473,],[94,94,94,94,94,94,94,94,94,94,94,94,94,94,]),'iteration_statement':([58,87,88,106,203,206,209,320,405,407,408,449,470,473,],[95,95,95,95,95,95,95,95,95,95,95,95,95,95,]),'jump_statement':([58,87,88,106,203,206,209,320,405,407,408,449,470,473,],[96,96,96,96,96,96,96,96,96,96,96,96,96,96,]),'expression':([58,87,88,103,106,111,167,203,206,209,212,215,216,218,236,238,245,249,320,329,405,407,408,409,410,449,470,473,484,],[101,101,101,213,101,223,213,101,101,101,323,326,327,101,333,335,213,213,101,101,101,101,101,448,450,101,101,101,488,]),'assignment_expression':([58,87,88,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,238,239,245,249,306,320,329,405,407,408,409,410,414,431,437,449,470,473,484,],[112,112,112,112,112,112,112,305,112,112,112,322,112,112,112,112,332,112,112,338,112,112,305,112,112,112,112,112,112,112,452,338,305,112,112,112,112,]),'conditional_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,238,239,245,249,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[113,164,164,113,113,164,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,164,164,113,164,113,113,164,164,164,113,113,113,113,113,451,113,113,113,164,113,113,113,113,]),'unary_expression':([58,60,69,87,88,99,103,106,111,117,118,119,121,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[114,166,166,114,114,166,114,114,114,244,246,166,248,114,114,114,114,114,114,114,114,114,114,114,114,166,114,114,114,114,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,114,166,114,166,114,166,166,166,114,114,114,114,114,166,114,114,114,166,114,114,114,114,]),'logical_or_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,238,239,245,249,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,]),'postfix_expression':([58,60,69,87,88,99,103,106,111,117,118,119,121,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,]),'unary_operator':([58,60,69,87,88,99,103,106,111,117,118,119,121,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,]),'cast_expression':([58,60,69,87,88,99,103,106,111,119,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[120,120,120,120,120,120,120,120,120,247,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,360,361,362,120,120,120,120,120,406,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,]),'asm_expression':([58,60,69,87,88,99,103,106,111,117,118,119,121,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,]),'logical_and_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,334,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,]),'primary_expression':([58,60,69,87,88,99,103,106,111,117,118,119,121,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,]),'string_literal':([58,60,69,87,88,99,103,106,111,117,118,119,121,136,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,344,366,376,399,405,407,408,409,410,411,414,431,437,442,449,455,470,473,484,485,487,492,],[132,132,132,132,132,132,132,132,132,132,132,132,132,254,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,416,132,132,132,132,132,132,132,132,132,132,132,132,132,132,474,132,132,132,474,474,474,]),'inclusive_or_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,343,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,]),'identifier':([58,60,69,87,88,99,103,106,111,117,118,119,121,167,189,203,206,207,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,258,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,318,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,348,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,]),'constant':([58,60,69,87,88,99,103,106,111,117,118,119,121,167,184,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,389,399,405,407,408,409,410,411,414,431,437,442,449,463,470,473,484,],[135,135,135,135,135,135,135,135,135,135,135,135,135,135,301,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,435,135,135,135,135,135,135,135,135,135,135,135,135,478,135,135,135,]),'multi_string_literal':([58,60,69,87,88,99,103,106,111,117,118,119,121,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,]),'exclusive_or_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,345,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,]),'macro_param':([58,60,69,87,88,99,103,106,111,117,118,119,121,136,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,271,272,273,284,286,306,314,320,325,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[150,150,150,150,150,150,150,150,150,150,150,150,150,255,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,]),'and_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,346,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,]),'equality_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,349,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,]),'relational_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,350,351,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,]),'shift_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,352,353,354,355,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,]),'additive_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,356,357,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,]),'multiplicative_expression':([58,60,69,87,88,99,103,106,111,167,189,203,206,209,211,212,215,216,218,224,236,237,238,239,245,249,250,253,257,259,261,262,263,264,265,266,267,268,269,270,284,286,306,314,320,329,366,376,399,405,407,408,409,410,411,414,431,437,442,449,470,473,484,],[158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,358,359,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,]),'type_name':([60,103,167,239,249,414,431,],[161,214,214,339,342,453,339,]),'constant_expression':([60,69,99,284,286,314,366,376,399,442,],[162,175,208,372,375,402,419,427,443,468,]),'specifier_qualifier_list':([60,103,167,192,239,249,307,308,311,392,400,414,431,],[163,163,163,310,163,163,310,310,310,310,310,163,163,]),'parameter_type_list':([70,283,299,367,],[177,370,370,421,]),'identifier_list':([70,],[179,]),'parameter_list':([70,283,299,367,],[180,180,180,180,]),'parameter_declaration':([70,283,295,299,367,],[182,182,383,182,182,]),'enumerator_list':([82,198,],[194,315,]),'enumerator_list_iso':([82,198,],[195,195,]),'enumerator':([82,198,313,],[196,196,401,]),'assignment_operator':([114,],[224,]),'volatile_opt':([131,],[251,]),'abstract_declarator':([163,183,368,385,],[277,297,422,422,]),'specifier_qualifier':([163,165,310,],[278,285,278,]),'direct_abstract_declarator':([163,183,279,298,368,385,],[280,280,364,364,280,280,]),'macro_parameter_list':([169,],[287,]),'pragma_pack_stack_args':([184,],[302,]),'initializer':([189,306,437,],[304,391,466,]),'member_declaration_list':([192,307,311,],[308,392,400,]),'member_declaration':([192,307,308,311,392,400,],[309,309,394,309,394,394,]),'argument_expression_list':([239,431,],[337,462,]),'gcc_attrib_list':([290,],[378,]),'gcc_attrib':([290,430,],[379,461,]),'initializer_list':([306,],[390,]),'member_declarator_list':([310,],[395,]),'member_declarator':([310,440,],[397,467,]),'str_opt_expr_pair_list':([455,485,492,],[475,489,494,]),'str_opt_expr_pair':([455,485,487,492,],[476,476,490,476,]),} +_lr_goto_items = {'translation_unit':([0,],[1,]),'external_declaration':([1,],[2,]),'directive':([1,],[3,]),'declaration':([1,11,23,58,61,84,96,],[4,60,60,93,60,93,93,]),'function_definition':([1,],[5,]),'define':([1,],[6,]),'undefine':([1,],[7,]),'pragma':([1,],[8,]),'declaration_impl':([1,11,23,58,61,84,96,],[9,9,9,9,9,9,9,]),'declaration_specifier_list':([1,11,23,58,61,79,84,96,292,308,312,376,],[10,62,62,62,62,193,62,62,193,193,193,193,]),'declarator':([1,10,62,66,87,193,319,398,449,],[11,23,166,178,166,309,407,178,407,]),'pragma_pack':([1,],[15,]),'gcc_attributes':([1,11,13,23,25,54,58,61,63,74,79,84,96,111,166,174,201,248,258,287,289,292,294,308,309,312,316,317,320,373,376,401,407,409,423,444,452,477,],[17,17,66,86,88,89,17,17,172,183,17,17,17,172,283,172,172,172,172,372,374,377,382,17,397,398,172,172,172,426,17,172,450,172,172,172,478,489,]),'pointer':([1,10,20,62,66,80,87,170,193,319,377,398,449,],[18,18,81,18,18,194,18,288,311,18,288,311,18,]),'direct_declarator':([1,10,18,62,66,87,193,311,319,398,449,],[19,19,77,19,19,19,19,77,19,19,19,]),'init_declarator_list':([10,62,],[24,24,]),'declaration_specifier':([10,17,62,86,193,377,398,],[25,74,25,74,25,74,74,]),'init_declarator':([10,62,87,],[26,26,199,]),'storage_class_specifier':([10,17,62,86,193,377,398,],[27,27,27,27,27,27,27,]),'type_specifier':([10,17,62,86,170,172,193,319,377,398,],[28,28,28,28,290,290,28,290,28,28,]),'type_qualifier':([10,17,20,62,80,86,170,172,193,319,377,398,],[29,29,82,29,195,29,291,291,29,291,29,29,]),'function_specifier':([10,17,62,86,193,377,398,],[30,30,30,30,30,30,30,]),'struct_or_union_specifier':([10,17,62,86,170,172,193,319,377,398,],[46,46,46,46,46,46,46,46,46,46,]),'enum_specifier':([10,17,62,86,170,172,193,319,377,398,],[47,47,47,47,47,47,47,47,47,47,]),'struct_or_union':([10,17,62,86,170,172,193,319,377,398,],[54,54,54,54,54,54,54,54,54,54,]),'declaration_list':([11,23,61,],[58,84,96,]),'compound_statement':([11,23,58,61,84,95,96,114,212,215,218,329,414,416,417,458,479,482,],[59,85,92,100,197,100,100,100,100,100,100,100,100,100,100,100,100,100,]),'pragma_directive_list':([16,],[68,]),'pragma_directive':([16,68,],[70,181,]),'string_literal':([16,61,63,68,78,95,96,107,111,114,119,125,126,127,129,144,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,353,375,385,408,414,416,417,418,419,420,423,444,446,451,458,464,479,482,493,494,496,501,],[72,140,140,72,140,140,140,140,140,140,140,140,140,140,140,263,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,425,140,140,140,140,140,140,140,140,140,140,140,140,140,140,483,140,140,140,483,483,483,]),'gcc_attribute':([17,20,66,80,86,88,89,172,183,283,372,374,377,382,397,398,426,450,478,489,],[75,83,75,196,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,]),'type_qualifier_list':([20,],[80,]),'statement_list':([61,96,],[95,212,]),'statement':([61,95,96,114,212,215,218,329,414,416,417,458,479,482,],[98,209,98,226,209,326,330,413,454,455,456,481,490,492,]),'labeled_statement':([61,95,96,114,212,215,218,329,414,416,417,458,479,482,],[99,99,99,99,99,99,99,99,99,99,99,99,99,99,]),'expression_statement':([61,95,96,114,212,215,218,227,329,338,414,416,417,458,479,482,],[101,101,101,101,101,101,101,338,101,419,101,101,101,101,101,101,]),'selection_statement':([61,95,96,114,212,215,218,329,414,416,417,458,479,482,],[102,102,102,102,102,102,102,102,102,102,102,102,102,102,]),'iteration_statement':([61,95,96,114,212,215,218,329,414,416,417,458,479,482,],[103,103,103,103,103,103,103,103,103,103,103,103,103,103,]),'jump_statement':([61,95,96,114,212,215,218,329,414,416,417,458,479,482,],[104,104,104,104,104,104,104,104,104,104,104,104,104,104,]),'expression':([61,95,96,111,114,119,174,212,215,218,221,224,225,227,245,247,254,258,329,338,414,416,417,418,419,458,479,482,493,],[109,109,109,222,109,232,222,109,109,109,332,335,336,109,342,344,222,222,109,109,109,109,109,457,459,109,109,109,497,]),'assignment_expression':([61,95,96,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,247,248,254,258,315,329,338,414,416,417,418,419,423,444,446,458,479,482,493,],[120,120,120,120,120,120,120,314,120,120,120,331,120,120,120,120,341,120,120,347,120,120,314,120,120,120,120,120,120,120,461,347,314,120,120,120,120,]),'conditional_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,247,248,254,258,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[121,171,171,121,121,171,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,171,171,121,171,121,121,171,171,171,121,121,121,121,121,460,121,121,121,171,121,121,121,121,]),'unary_expression':([61,63,78,95,96,107,111,114,119,125,126,127,129,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[122,173,173,122,122,173,122,122,122,253,255,173,257,122,122,122,122,122,122,122,122,122,122,122,122,173,122,122,122,122,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,122,173,122,173,122,173,173,173,122,122,122,122,122,173,122,122,122,173,122,122,122,122,]),'logical_or_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,247,248,254,258,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,]),'postfix_expression':([61,63,78,95,96,107,111,114,119,125,126,127,129,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,]),'unary_operator':([61,63,78,95,96,107,111,114,119,125,126,127,129,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,]),'cast_expression':([61,63,78,95,96,107,111,114,119,127,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[128,128,128,128,128,128,128,128,128,256,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,369,370,371,128,128,128,128,128,415,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,]),'asm_expression':([61,63,78,95,96,107,111,114,119,125,126,127,129,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,]),'logical_and_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,343,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,]),'primary_expression':([61,63,78,95,96,107,111,114,119,125,126,127,129,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,]),'inclusive_or_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,352,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,]),'identifier':([61,63,78,95,96,107,111,114,119,125,126,127,129,174,198,212,215,216,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,267,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,327,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,357,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,]),'constant':([61,63,78,95,96,107,111,114,119,125,126,127,129,174,182,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,390,408,414,416,417,418,419,420,423,444,446,451,458,469,479,482,493,],[143,143,143,143,143,143,143,143,143,143,143,143,143,143,300,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,441,143,143,143,143,143,143,143,143,143,143,143,143,486,143,143,143,]),'multi_string_literal':([61,63,78,95,96,107,111,114,119,125,126,127,129,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,]),'exclusive_or_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,354,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,]),'macro_param':([61,63,78,95,96,107,111,114,119,125,126,127,129,144,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,280,281,282,293,295,315,323,329,334,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[158,158,158,158,158,158,158,158,158,158,158,158,158,264,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,]),'and_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,355,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,]),'equality_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,358,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,]),'relational_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,359,360,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,]),'shift_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,361,362,363,364,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,]),'additive_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,365,366,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,]),'multiplicative_expression':([61,63,78,95,96,107,111,114,119,174,198,212,215,218,220,221,224,225,227,233,245,246,247,248,254,258,259,262,266,268,270,271,272,273,274,275,276,277,278,279,293,295,315,323,329,338,375,385,408,414,416,417,418,419,420,423,444,446,451,458,479,482,493,],[165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,367,368,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,]),'type_name':([63,111,174,248,258,423,444,],[168,223,223,348,351,462,348,]),'constant_expression':([63,78,107,293,295,323,375,385,408,451,],[169,185,217,381,384,411,428,436,452,477,]),'specifier_qualifier_list':([63,111,174,201,248,258,316,317,320,401,409,423,444,],[170,170,170,319,170,170,319,319,319,319,319,170,170,]),'parameter_type_list':([79,292,312,376,],[187,379,379,430,]),'identifier_list':([79,],[189,]),'parameter_list':([79,292,312,376,],[190,190,190,190,]),'parameter_declaration':([79,292,308,312,376,],[192,192,396,192,192,]),'enumerator_list':([90,207,],[203,324,]),'enumerator_list_iso':([90,207,],[204,204,]),'enumerator':([90,207,322,],[205,205,410,]),'assignment_operator':([122,],[233,]),'volatile_opt':([139,],[260,]),'abstract_declarator':([170,193,377,398,],[286,310,431,431,]),'specifier_qualifier':([170,172,319,],[287,294,287,]),'direct_abstract_declarator':([170,193,288,311,377,398,],[289,289,373,373,289,289,]),'macro_parameter_list':([176,],[296,]),'pragma_pack_stack_args':([182,],[301,]),'initializer':([198,315,446,],[313,400,475,]),'member_declaration_list':([201,316,320,],[317,401,409,]),'member_declaration':([201,316,317,320,401,409,],[318,318,403,318,403,403,]),'argument_expression_list':([248,444,],[346,473,]),'gcc_attrib_list':([303,],[391,]),'gcc_attrib':([303,443,],[392,472,]),'initializer_list':([315,],[399,]),'member_declarator_list':([319,],[404,]),'member_declarator':([319,449,],[406,476,]),'str_opt_expr_pair_list':([464,494,501,],[484,498,503,]),'str_opt_expr_pair':([464,494,496,501,],[485,485,499,485,]),} _lr_goto = {} for _k, _v in _lr_goto_items.items(): @@ -27,295 +27,303 @@ del _lr_goto_items _lr_productions = [ ("S' -> translation_unit","S'",1,None,None,None), - ('translation_unit -> ','translation_unit',0,'p_translation_unit','cgrammar.py',122), - ('translation_unit -> translation_unit external_declaration','translation_unit',2,'p_translation_unit','cgrammar.py',123), - ('translation_unit -> translation_unit directive','translation_unit',2,'p_translation_unit','cgrammar.py',124), - ('identifier -> IDENTIFIER','identifier',1,'p_identifier','cgrammar.py',133), - ('identifier -> IDENTIFIER PP_IDENTIFIER_PASTE identifier','identifier',3,'p_identifier','cgrammar.py',134), - ('identifier -> PP_MACRO_PARAM PP_IDENTIFIER_PASTE identifier','identifier',3,'p_identifier','cgrammar.py',135), - ('identifier -> IDENTIFIER PP_IDENTIFIER_PASTE PP_MACRO_PARAM','identifier',3,'p_identifier','cgrammar.py',136), - ('identifier -> PP_MACRO_PARAM PP_IDENTIFIER_PASTE PP_MACRO_PARAM','identifier',3,'p_identifier','cgrammar.py',137), - ('constant -> I_CONST_HEX','constant',1,'p_constant_integer','cgrammar.py',155), - ('constant -> I_CONST_DEC','constant',1,'p_constant_integer','cgrammar.py',156), - ('constant -> I_CONST_OCT','constant',1,'p_constant_integer','cgrammar.py',157), - ('constant -> I_CONST_BIN','constant',1,'p_constant_integer','cgrammar.py',158), - ('constant -> F_CONST_1','constant',1,'p_constant_float','cgrammar.py',171), - ('constant -> F_CONST_2','constant',1,'p_constant_float','cgrammar.py',172), - ('constant -> F_CONST_3','constant',1,'p_constant_float','cgrammar.py',173), - ('constant -> F_CONST_4','constant',1,'p_constant_float','cgrammar.py',174), - ('constant -> F_CONST_5','constant',1,'p_constant_float','cgrammar.py',175), - ('constant -> F_CONST_6','constant',1,'p_constant_float','cgrammar.py',176), - ('constant -> CHARACTER_CONSTANT','constant',1,'p_constant_character','cgrammar.py',182), - ('string_literal -> STRING_LITERAL','string_literal',1,'p_string_literal','cgrammar.py',190), - ('multi_string_literal -> string_literal','multi_string_literal',1,'p_multi_string_literal','cgrammar.py',196), - ('multi_string_literal -> macro_param','multi_string_literal',1,'p_multi_string_literal','cgrammar.py',197), - ('multi_string_literal -> multi_string_literal string_literal','multi_string_literal',2,'p_multi_string_literal','cgrammar.py',198), - ('multi_string_literal -> multi_string_literal macro_param','multi_string_literal',2,'p_multi_string_literal','cgrammar.py',199), - ('macro_param -> PP_MACRO_PARAM','macro_param',1,'p_macro_param','cgrammar.py',210), - ('macro_param -> PP_STRINGIFY PP_MACRO_PARAM','macro_param',2,'p_macro_param','cgrammar.py',211), - ('primary_expression -> identifier','primary_expression',1,'p_primary_expression','cgrammar.py',220), - ('primary_expression -> constant','primary_expression',1,'p_primary_expression','cgrammar.py',221), - ('primary_expression -> multi_string_literal','primary_expression',1,'p_primary_expression','cgrammar.py',222), - ('primary_expression -> LPAREN expression RPAREN','primary_expression',3,'p_primary_expression','cgrammar.py',223), - ('postfix_expression -> primary_expression','postfix_expression',1,'p_postfix_expression','cgrammar.py',232), - ('postfix_expression -> postfix_expression LBRACKET expression RBRACKET','postfix_expression',4,'p_postfix_expression','cgrammar.py',233), - ('postfix_expression -> postfix_expression LPAREN RPAREN','postfix_expression',3,'p_postfix_expression','cgrammar.py',234), - ('postfix_expression -> postfix_expression LPAREN argument_expression_list RPAREN','postfix_expression',4,'p_postfix_expression','cgrammar.py',235), - ('postfix_expression -> postfix_expression PERIOD IDENTIFIER','postfix_expression',3,'p_postfix_expression','cgrammar.py',236), - ('postfix_expression -> postfix_expression PTR_OP IDENTIFIER','postfix_expression',3,'p_postfix_expression','cgrammar.py',237), - ('postfix_expression -> postfix_expression INC_OP','postfix_expression',2,'p_postfix_expression','cgrammar.py',238), - ('postfix_expression -> postfix_expression DEC_OP','postfix_expression',2,'p_postfix_expression','cgrammar.py',239), - ('argument_expression_list -> assignment_expression','argument_expression_list',1,'p_argument_expression_list','cgrammar.py',278), - ('argument_expression_list -> argument_expression_list COMMA assignment_expression','argument_expression_list',3,'p_argument_expression_list','cgrammar.py',279), - ('argument_expression_list -> type_name','argument_expression_list',1,'p_argument_expression_list','cgrammar.py',280), - ('argument_expression_list -> argument_expression_list COMMA type_name','argument_expression_list',3,'p_argument_expression_list','cgrammar.py',281), - ('asm_expression -> __ASM__ volatile_opt LPAREN string_literal RPAREN','asm_expression',5,'p_asm_expression','cgrammar.py',291), - ('asm_expression -> __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list RPAREN','asm_expression',7,'p_asm_expression','cgrammar.py',292), - ('asm_expression -> __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list RPAREN','asm_expression',9,'p_asm_expression','cgrammar.py',293), - ('asm_expression -> __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list RPAREN','asm_expression',11,'p_asm_expression','cgrammar.py',294), - ('str_opt_expr_pair_list -> ','str_opt_expr_pair_list',0,'p_str_opt_expr_pair_list','cgrammar.py',307), - ('str_opt_expr_pair_list -> str_opt_expr_pair','str_opt_expr_pair_list',1,'p_str_opt_expr_pair_list','cgrammar.py',308), - ('str_opt_expr_pair_list -> str_opt_expr_pair_list COMMA str_opt_expr_pair','str_opt_expr_pair_list',3,'p_str_opt_expr_pair_list','cgrammar.py',309), - ('str_opt_expr_pair -> string_literal','str_opt_expr_pair',1,'p_str_opt_expr_pair','cgrammar.py',314), - ('str_opt_expr_pair -> string_literal LPAREN expression RPAREN','str_opt_expr_pair',4,'p_str_opt_expr_pair','cgrammar.py',315), - ('volatile_opt -> ','volatile_opt',0,'p_volatile_opt','cgrammar.py',320), - ('volatile_opt -> VOLATILE','volatile_opt',1,'p_volatile_opt','cgrammar.py',321), - ('unary_expression -> postfix_expression','unary_expression',1,'p_unary_expression','cgrammar.py',338), - ('unary_expression -> INC_OP unary_expression','unary_expression',2,'p_unary_expression','cgrammar.py',339), - ('unary_expression -> DEC_OP unary_expression','unary_expression',2,'p_unary_expression','cgrammar.py',340), - ('unary_expression -> unary_operator cast_expression','unary_expression',2,'p_unary_expression','cgrammar.py',341), - ('unary_expression -> SIZEOF unary_expression','unary_expression',2,'p_unary_expression','cgrammar.py',342), - ('unary_expression -> SIZEOF LPAREN type_name RPAREN','unary_expression',4,'p_unary_expression','cgrammar.py',343), - ('unary_expression -> asm_expression','unary_expression',1,'p_unary_expression','cgrammar.py',344), - ('unary_operator -> AND','unary_operator',1,'p_unary_operator','cgrammar.py',361), - ('unary_operator -> TIMES','unary_operator',1,'p_unary_operator','cgrammar.py',362), - ('unary_operator -> PLUS','unary_operator',1,'p_unary_operator','cgrammar.py',363), - ('unary_operator -> MINUS','unary_operator',1,'p_unary_operator','cgrammar.py',364), - ('unary_operator -> NOT','unary_operator',1,'p_unary_operator','cgrammar.py',365), - ('unary_operator -> LNOT','unary_operator',1,'p_unary_operator','cgrammar.py',366), - ('cast_expression -> unary_expression','cast_expression',1,'p_cast_expression','cgrammar.py',372), - ('cast_expression -> LPAREN type_name RPAREN cast_expression','cast_expression',4,'p_cast_expression','cgrammar.py',373), - ('multiplicative_expression -> cast_expression','multiplicative_expression',1,'p_multiplicative_expression','cgrammar.py',389), - ('multiplicative_expression -> multiplicative_expression TIMES cast_expression','multiplicative_expression',3,'p_multiplicative_expression','cgrammar.py',390), - ('multiplicative_expression -> multiplicative_expression DIVIDE cast_expression','multiplicative_expression',3,'p_multiplicative_expression','cgrammar.py',391), - ('multiplicative_expression -> multiplicative_expression MOD cast_expression','multiplicative_expression',3,'p_multiplicative_expression','cgrammar.py',392), - ('additive_expression -> multiplicative_expression','additive_expression',1,'p_additive_expression','cgrammar.py',408), - ('additive_expression -> additive_expression PLUS multiplicative_expression','additive_expression',3,'p_additive_expression','cgrammar.py',409), - ('additive_expression -> additive_expression MINUS multiplicative_expression','additive_expression',3,'p_additive_expression','cgrammar.py',410), - ('shift_expression -> additive_expression','shift_expression',1,'p_shift_expression','cgrammar.py',426), - ('shift_expression -> shift_expression LEFT_OP additive_expression','shift_expression',3,'p_shift_expression','cgrammar.py',427), - ('shift_expression -> shift_expression RIGHT_OP additive_expression','shift_expression',3,'p_shift_expression','cgrammar.py',428), - ('relational_expression -> shift_expression','relational_expression',1,'p_relational_expression','cgrammar.py',446), - ('relational_expression -> relational_expression LT shift_expression','relational_expression',3,'p_relational_expression','cgrammar.py',447), - ('relational_expression -> relational_expression GT shift_expression','relational_expression',3,'p_relational_expression','cgrammar.py',448), - ('relational_expression -> relational_expression LE_OP shift_expression','relational_expression',3,'p_relational_expression','cgrammar.py',449), - ('relational_expression -> relational_expression GE_OP shift_expression','relational_expression',3,'p_relational_expression','cgrammar.py',450), - ('equality_expression -> relational_expression','equality_expression',1,'p_equality_expression','cgrammar.py',466), - ('equality_expression -> equality_expression EQ_OP relational_expression','equality_expression',3,'p_equality_expression','cgrammar.py',467), - ('equality_expression -> equality_expression NE_OP relational_expression','equality_expression',3,'p_equality_expression','cgrammar.py',468), - ('and_expression -> equality_expression','and_expression',1,'p_and_expression','cgrammar.py',478), - ('and_expression -> and_expression AND equality_expression','and_expression',3,'p_and_expression','cgrammar.py',479), - ('exclusive_or_expression -> and_expression','exclusive_or_expression',1,'p_exclusive_or_expression','cgrammar.py',490), - ('exclusive_or_expression -> exclusive_or_expression XOR and_expression','exclusive_or_expression',3,'p_exclusive_or_expression','cgrammar.py',491), - ('inclusive_or_expression -> exclusive_or_expression','inclusive_or_expression',1,'p_inclusive_or_expression','cgrammar.py',502), - ('inclusive_or_expression -> inclusive_or_expression OR exclusive_or_expression','inclusive_or_expression',3,'p_inclusive_or_expression','cgrammar.py',503), - ('logical_and_expression -> inclusive_or_expression','logical_and_expression',1,'p_logical_and_expression','cgrammar.py',514), - ('logical_and_expression -> logical_and_expression AND_OP inclusive_or_expression','logical_and_expression',3,'p_logical_and_expression','cgrammar.py',515), - ('logical_or_expression -> logical_and_expression','logical_or_expression',1,'p_logical_or_expression','cgrammar.py',526), - ('logical_or_expression -> logical_or_expression OR_OP logical_and_expression','logical_or_expression',3,'p_logical_or_expression','cgrammar.py',527), - ('conditional_expression -> logical_or_expression','conditional_expression',1,'p_conditional_expression','cgrammar.py',538), - ('conditional_expression -> logical_or_expression CONDOP expression COLON conditional_expression','conditional_expression',5,'p_conditional_expression','cgrammar.py',539), - ('assignment_expression -> conditional_expression','assignment_expression',1,'p_assignment_expression','cgrammar.py',562), - ('assignment_expression -> unary_expression assignment_operator assignment_expression','assignment_expression',3,'p_assignment_expression','cgrammar.py',563), - ('assignment_operator -> EQUALS','assignment_operator',1,'p_assignment_operator','cgrammar.py',578), - ('assignment_operator -> MUL_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',579), - ('assignment_operator -> DIV_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',580), - ('assignment_operator -> MOD_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',581), - ('assignment_operator -> ADD_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',582), - ('assignment_operator -> SUB_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',583), - ('assignment_operator -> LEFT_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',584), - ('assignment_operator -> RIGHT_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',585), - ('assignment_operator -> AND_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',586), - ('assignment_operator -> XOR_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',587), - ('assignment_operator -> OR_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',588), - ('expression -> assignment_expression','expression',1,'p_expression','cgrammar.py',594), - ('expression -> expression COMMA assignment_expression','expression',3,'p_expression','cgrammar.py',595), - ('constant_expression -> conditional_expression','constant_expression',1,'p_constant_expression','cgrammar.py',602), - ('declaration -> declaration_impl SEMI','declaration',2,'p_declaration','cgrammar.py',608), - ('declaration_impl -> declaration_specifier_list','declaration_impl',1,'p_declaration_impl','cgrammar.py',616), - ('declaration_impl -> declaration_specifier_list init_declarator_list','declaration_impl',2,'p_declaration_impl','cgrammar.py',617), - ('declaration_specifier_list -> gcc_attributes declaration_specifier gcc_attributes','declaration_specifier_list',3,'p_declaration_specifier_list','cgrammar.py',636), - ('declaration_specifier_list -> declaration_specifier_list declaration_specifier gcc_attributes','declaration_specifier_list',3,'p_declaration_specifier_list','cgrammar.py',637), - ('declaration_specifier -> storage_class_specifier','declaration_specifier',1,'p_declaration_specifier','cgrammar.py',650), - ('declaration_specifier -> type_specifier','declaration_specifier',1,'p_declaration_specifier','cgrammar.py',651), - ('declaration_specifier -> type_qualifier','declaration_specifier',1,'p_declaration_specifier','cgrammar.py',652), - ('init_declarator_list -> init_declarator','init_declarator_list',1,'p_init_declarator_list','cgrammar.py',658), - ('init_declarator_list -> init_declarator_list COMMA init_declarator','init_declarator_list',3,'p_init_declarator_list','cgrammar.py',659), - ('init_declarator -> declarator gcc_attributes','init_declarator',2,'p_init_declarator','cgrammar.py',668), - ('init_declarator -> declarator gcc_attributes EQUALS initializer','init_declarator',4,'p_init_declarator','cgrammar.py',669), - ('storage_class_specifier -> TYPEDEF','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',680), - ('storage_class_specifier -> EXTERN','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',681), - ('storage_class_specifier -> STATIC','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',682), - ('storage_class_specifier -> AUTO','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',683), - ('storage_class_specifier -> REGISTER','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',684), - ('type_specifier -> VOID','type_specifier',1,'p_type_specifier','cgrammar.py',690), - ('type_specifier -> _BOOL','type_specifier',1,'p_type_specifier','cgrammar.py',691), - ('type_specifier -> CHAR','type_specifier',1,'p_type_specifier','cgrammar.py',692), - ('type_specifier -> SHORT','type_specifier',1,'p_type_specifier','cgrammar.py',693), - ('type_specifier -> INT','type_specifier',1,'p_type_specifier','cgrammar.py',694), - ('type_specifier -> LONG','type_specifier',1,'p_type_specifier','cgrammar.py',695), - ('type_specifier -> FLOAT','type_specifier',1,'p_type_specifier','cgrammar.py',696), - ('type_specifier -> DOUBLE','type_specifier',1,'p_type_specifier','cgrammar.py',697), - ('type_specifier -> SIGNED','type_specifier',1,'p_type_specifier','cgrammar.py',698), - ('type_specifier -> UNSIGNED','type_specifier',1,'p_type_specifier','cgrammar.py',699), - ('type_specifier -> struct_or_union_specifier','type_specifier',1,'p_type_specifier','cgrammar.py',700), - ('type_specifier -> enum_specifier','type_specifier',1,'p_type_specifier','cgrammar.py',701), - ('type_specifier -> TYPE_NAME','type_specifier',1,'p_type_specifier','cgrammar.py',702), - ('struct_or_union_specifier -> struct_or_union gcc_attributes IDENTIFIER LBRACE member_declaration_list RBRACE','struct_or_union_specifier',6,'p_struct_or_union_specifier','cgrammar.py',711), - ('struct_or_union_specifier -> struct_or_union gcc_attributes TYPE_NAME LBRACE member_declaration_list RBRACE','struct_or_union_specifier',6,'p_struct_or_union_specifier','cgrammar.py',712), - ('struct_or_union_specifier -> struct_or_union gcc_attributes LBRACE member_declaration_list RBRACE','struct_or_union_specifier',5,'p_struct_or_union_specifier','cgrammar.py',713), - ('struct_or_union_specifier -> struct_or_union gcc_attributes IDENTIFIER','struct_or_union_specifier',3,'p_struct_or_union_specifier','cgrammar.py',714), - ('struct_or_union_specifier -> struct_or_union gcc_attributes TYPE_NAME','struct_or_union_specifier',3,'p_struct_or_union_specifier','cgrammar.py',715), - ('struct_or_union -> STRUCT','struct_or_union',1,'p_struct_or_union','cgrammar.py',740), - ('struct_or_union -> UNION','struct_or_union',1,'p_struct_or_union','cgrammar.py',741), - ('gcc_attributes -> ','gcc_attributes',0,'p_gcc_attributes','cgrammar.py',747), - ('gcc_attributes -> gcc_attributes gcc_attribute','gcc_attributes',2,'p_gcc_attributes','cgrammar.py',748), - ('gcc_attribute -> __ATTRIBUTE__ LPAREN LPAREN gcc_attrib_list RPAREN RPAREN','gcc_attribute',6,'p_gcc_attribute','cgrammar.py',759), - ('gcc_attrib_list -> gcc_attrib','gcc_attrib_list',1,'p_gcc_attrib_list','cgrammar.py',766), - ('gcc_attrib_list -> gcc_attrib_list COMMA gcc_attrib','gcc_attrib_list',3,'p_gcc_attrib_list','cgrammar.py',767), - ('gcc_attrib -> ','gcc_attrib',0,'p_gcc_attrib','cgrammar.py',776), - ('gcc_attrib -> IDENTIFIER','gcc_attrib',1,'p_gcc_attrib','cgrammar.py',777), - ('gcc_attrib -> IDENTIFIER LPAREN argument_expression_list RPAREN','gcc_attrib',4,'p_gcc_attrib','cgrammar.py',778), - ('member_declaration_list -> member_declaration','member_declaration_list',1,'p_member_declaration_list','cgrammar.py',791), - ('member_declaration_list -> member_declaration_list member_declaration','member_declaration_list',2,'p_member_declaration_list','cgrammar.py',792), - ('member_declaration -> specifier_qualifier_list member_declarator_list SEMI','member_declaration',3,'p_member_declaration','cgrammar.py',801), - ('member_declaration -> specifier_qualifier_list SEMI','member_declaration',2,'p_member_declaration','cgrammar.py',802), - ('specifier_qualifier_list -> gcc_attributes specifier_qualifier gcc_attributes','specifier_qualifier_list',3,'p_specifier_qualifier_list','cgrammar.py',823), - ('specifier_qualifier_list -> specifier_qualifier_list specifier_qualifier gcc_attributes','specifier_qualifier_list',3,'p_specifier_qualifier_list','cgrammar.py',824), - ('specifier_qualifier -> type_specifier','specifier_qualifier',1,'p_specifier_qualifier','cgrammar.py',833), - ('specifier_qualifier -> type_qualifier','specifier_qualifier',1,'p_specifier_qualifier','cgrammar.py',834), - ('member_declarator_list -> member_declarator','member_declarator_list',1,'p_member_declarator_list','cgrammar.py',840), - ('member_declarator_list -> member_declarator_list COMMA member_declarator','member_declarator_list',3,'p_member_declarator_list','cgrammar.py',841), - ('member_declarator -> declarator gcc_attributes','member_declarator',2,'p_member_declarator','cgrammar.py',850), - ('member_declarator -> COLON constant_expression gcc_attributes','member_declarator',3,'p_member_declarator','cgrammar.py',851), - ('member_declarator -> declarator COLON constant_expression gcc_attributes','member_declarator',4,'p_member_declarator','cgrammar.py',852), - ('enum_specifier -> ENUM LBRACE enumerator_list RBRACE','enum_specifier',4,'p_enum_specifier','cgrammar.py',867), - ('enum_specifier -> ENUM IDENTIFIER LBRACE enumerator_list RBRACE','enum_specifier',5,'p_enum_specifier','cgrammar.py',868), - ('enum_specifier -> ENUM IDENTIFIER','enum_specifier',2,'p_enum_specifier','cgrammar.py',869), - ('enumerator_list -> enumerator_list_iso','enumerator_list',1,'p_enumerator_list','cgrammar.py',883), - ('enumerator_list -> enumerator_list_iso COMMA','enumerator_list',2,'p_enumerator_list','cgrammar.py',884), - ('enumerator_list_iso -> enumerator','enumerator_list_iso',1,'p_enumerator_list_iso','cgrammar.py',892), - ('enumerator_list_iso -> enumerator_list_iso COMMA enumerator','enumerator_list_iso',3,'p_enumerator_list_iso','cgrammar.py',893), - ('enumerator -> IDENTIFIER','enumerator',1,'p_enumerator','cgrammar.py',902), - ('enumerator -> IDENTIFIER EQUALS constant_expression','enumerator',3,'p_enumerator','cgrammar.py',903), - ('type_qualifier -> CONST','type_qualifier',1,'p_type_qualifier','cgrammar.py',912), - ('type_qualifier -> VOLATILE','type_qualifier',1,'p_type_qualifier','cgrammar.py',913), - ('type_qualifier -> RESTRICT','type_qualifier',1,'p_type_qualifier','cgrammar.py',914), - ('declarator -> pointer direct_declarator','declarator',2,'p_declarator','cgrammar.py',920), - ('declarator -> direct_declarator','declarator',1,'p_declarator','cgrammar.py',921), - ('direct_declarator -> IDENTIFIER','direct_declarator',1,'p_direct_declarator','cgrammar.py',935), - ('direct_declarator -> LPAREN gcc_attributes declarator RPAREN','direct_declarator',4,'p_direct_declarator','cgrammar.py',936), - ('direct_declarator -> direct_declarator LBRACKET constant_expression RBRACKET','direct_declarator',4,'p_direct_declarator','cgrammar.py',937), - ('direct_declarator -> direct_declarator LBRACKET RBRACKET','direct_declarator',3,'p_direct_declarator','cgrammar.py',938), - ('direct_declarator -> direct_declarator LPAREN parameter_type_list RPAREN','direct_declarator',4,'p_direct_declarator','cgrammar.py',939), - ('direct_declarator -> direct_declarator LPAREN identifier_list RPAREN','direct_declarator',4,'p_direct_declarator','cgrammar.py',940), - ('direct_declarator -> direct_declarator LPAREN RPAREN','direct_declarator',3,'p_direct_declarator','cgrammar.py',941), - ('pointer -> TIMES','pointer',1,'p_pointer','cgrammar.py',971), - ('pointer -> TIMES type_qualifier_list','pointer',2,'p_pointer','cgrammar.py',972), - ('pointer -> TIMES pointer','pointer',2,'p_pointer','cgrammar.py',973), - ('pointer -> TIMES type_qualifier_list pointer','pointer',3,'p_pointer','cgrammar.py',974), - ('type_qualifier_list -> type_qualifier','type_qualifier_list',1,'p_type_qualifier_list','cgrammar.py',996), - ('type_qualifier_list -> gcc_attribute','type_qualifier_list',1,'p_type_qualifier_list','cgrammar.py',997), - ('type_qualifier_list -> type_qualifier_list type_qualifier','type_qualifier_list',2,'p_type_qualifier_list','cgrammar.py',998), - ('type_qualifier_list -> type_qualifier_list gcc_attribute','type_qualifier_list',2,'p_type_qualifier_list','cgrammar.py',999), - ('parameter_type_list -> parameter_list','parameter_type_list',1,'p_parameter_type_list','cgrammar.py',1008), - ('parameter_type_list -> parameter_list COMMA ELLIPSIS','parameter_type_list',3,'p_parameter_type_list','cgrammar.py',1009), - ('parameter_list -> parameter_declaration','parameter_list',1,'p_parameter_list','cgrammar.py',1018), - ('parameter_list -> parameter_list COMMA parameter_declaration','parameter_list',3,'p_parameter_list','cgrammar.py',1019), - ('parameter_declaration -> declaration_specifier_list declarator gcc_attributes','parameter_declaration',3,'p_parameter_declaration','cgrammar.py',1028), - ('parameter_declaration -> declaration_specifier_list abstract_declarator','parameter_declaration',2,'p_parameter_declaration','cgrammar.py',1029), - ('parameter_declaration -> declaration_specifier_list','parameter_declaration',1,'p_parameter_declaration','cgrammar.py',1030), - ('identifier_list -> IDENTIFIER','identifier_list',1,'p_identifier_list','cgrammar.py',1046), - ('identifier_list -> identifier_list COMMA IDENTIFIER','identifier_list',3,'p_identifier_list','cgrammar.py',1047), - ('type_name -> specifier_qualifier_list','type_name',1,'p_type_name','cgrammar.py',1060), - ('type_name -> specifier_qualifier_list abstract_declarator','type_name',2,'p_type_name','cgrammar.py',1061), - ('abstract_declarator -> pointer','abstract_declarator',1,'p_abstract_declarator','cgrammar.py',1077), - ('abstract_declarator -> direct_abstract_declarator gcc_attributes','abstract_declarator',2,'p_abstract_declarator','cgrammar.py',1078), - ('abstract_declarator -> pointer direct_abstract_declarator gcc_attributes','abstract_declarator',3,'p_abstract_declarator','cgrammar.py',1079), - ('direct_abstract_declarator -> LPAREN gcc_attributes abstract_declarator RPAREN','direct_abstract_declarator',4,'p_direct_abstract_declarator','cgrammar.py',1106), - ('direct_abstract_declarator -> LBRACKET RBRACKET','direct_abstract_declarator',2,'p_direct_abstract_declarator','cgrammar.py',1107), - ('direct_abstract_declarator -> LBRACKET constant_expression RBRACKET','direct_abstract_declarator',3,'p_direct_abstract_declarator','cgrammar.py',1108), - ('direct_abstract_declarator -> direct_abstract_declarator LBRACKET RBRACKET','direct_abstract_declarator',3,'p_direct_abstract_declarator','cgrammar.py',1109), - ('direct_abstract_declarator -> direct_abstract_declarator LBRACKET constant_expression RBRACKET','direct_abstract_declarator',4,'p_direct_abstract_declarator','cgrammar.py',1110), - ('direct_abstract_declarator -> LPAREN RPAREN','direct_abstract_declarator',2,'p_direct_abstract_declarator','cgrammar.py',1111), - ('direct_abstract_declarator -> LPAREN parameter_type_list RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator','cgrammar.py',1112), - ('direct_abstract_declarator -> direct_abstract_declarator LPAREN RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator','cgrammar.py',1113), - ('direct_abstract_declarator -> direct_abstract_declarator LPAREN parameter_type_list RPAREN','direct_abstract_declarator',4,'p_direct_abstract_declarator','cgrammar.py',1114), - ('initializer -> assignment_expression','initializer',1,'p_initializer','cgrammar.py',1153), - ('initializer -> LBRACE initializer_list RBRACE','initializer',3,'p_initializer','cgrammar.py',1154), - ('initializer -> LBRACE initializer_list COMMA RBRACE','initializer',4,'p_initializer','cgrammar.py',1155), - ('initializer_list -> initializer','initializer_list',1,'p_initializer_list','cgrammar.py',1160), - ('initializer_list -> initializer_list COMMA initializer','initializer_list',3,'p_initializer_list','cgrammar.py',1161), - ('statement -> labeled_statement','statement',1,'p_statement','cgrammar.py',1166), - ('statement -> compound_statement','statement',1,'p_statement','cgrammar.py',1167), - ('statement -> expression_statement','statement',1,'p_statement','cgrammar.py',1168), - ('statement -> selection_statement','statement',1,'p_statement','cgrammar.py',1169), - ('statement -> iteration_statement','statement',1,'p_statement','cgrammar.py',1170), - ('statement -> jump_statement','statement',1,'p_statement','cgrammar.py',1171), - ('labeled_statement -> IDENTIFIER COLON statement','labeled_statement',3,'p_labeled_statement','cgrammar.py',1176), - ('labeled_statement -> CASE constant_expression COLON statement','labeled_statement',4,'p_labeled_statement','cgrammar.py',1177), - ('labeled_statement -> DEFAULT COLON statement','labeled_statement',3,'p_labeled_statement','cgrammar.py',1178), - ('compound_statement -> LBRACE RBRACE','compound_statement',2,'p_compound_statement','cgrammar.py',1183), - ('compound_statement -> LBRACE statement_list RBRACE','compound_statement',3,'p_compound_statement','cgrammar.py',1184), - ('compound_statement -> LBRACE declaration_list RBRACE','compound_statement',3,'p_compound_statement','cgrammar.py',1185), - ('compound_statement -> LBRACE declaration_list statement_list RBRACE','compound_statement',4,'p_compound_statement','cgrammar.py',1186), - ('compound_statement -> LBRACE error RBRACE','compound_statement',3,'p_compound_statement_error','cgrammar.py',1191), - ('declaration_list -> declaration','declaration_list',1,'p_declaration_list','cgrammar.py',1197), - ('declaration_list -> declaration_list declaration','declaration_list',2,'p_declaration_list','cgrammar.py',1198), - ('statement_list -> statement','statement_list',1,'p_statement_list','cgrammar.py',1203), - ('statement_list -> statement_list statement','statement_list',2,'p_statement_list','cgrammar.py',1204), - ('expression_statement -> SEMI','expression_statement',1,'p_expression_statement','cgrammar.py',1209), - ('expression_statement -> expression SEMI','expression_statement',2,'p_expression_statement','cgrammar.py',1210), - ('expression_statement -> error SEMI','expression_statement',2,'p_expression_statement_error','cgrammar.py',1215), - ('selection_statement -> IF LPAREN expression RPAREN statement','selection_statement',5,'p_selection_statement','cgrammar.py',1221), - ('selection_statement -> IF LPAREN expression RPAREN statement ELSE statement','selection_statement',7,'p_selection_statement','cgrammar.py',1222), - ('selection_statement -> SWITCH LPAREN expression RPAREN statement','selection_statement',5,'p_selection_statement','cgrammar.py',1223), - ('iteration_statement -> WHILE LPAREN expression RPAREN statement','iteration_statement',5,'p_iteration_statement','cgrammar.py',1228), - ('iteration_statement -> DO statement WHILE LPAREN expression RPAREN SEMI','iteration_statement',7,'p_iteration_statement','cgrammar.py',1229), - ('iteration_statement -> FOR LPAREN expression_statement expression_statement RPAREN statement','iteration_statement',6,'p_iteration_statement','cgrammar.py',1230), - ('iteration_statement -> FOR LPAREN expression_statement expression_statement expression RPAREN statement','iteration_statement',7,'p_iteration_statement','cgrammar.py',1231), - ('jump_statement -> GOTO IDENTIFIER SEMI','jump_statement',3,'p_jump_statement','cgrammar.py',1236), - ('jump_statement -> CONTINUE SEMI','jump_statement',2,'p_jump_statement','cgrammar.py',1237), - ('jump_statement -> BREAK SEMI','jump_statement',2,'p_jump_statement','cgrammar.py',1238), - ('jump_statement -> RETURN SEMI','jump_statement',2,'p_jump_statement','cgrammar.py',1239), - ('jump_statement -> RETURN expression SEMI','jump_statement',3,'p_jump_statement','cgrammar.py',1240), - ('external_declaration -> declaration','external_declaration',1,'p_external_declaration','cgrammar.py',1245), - ('external_declaration -> function_definition','external_declaration',1,'p_external_declaration','cgrammar.py',1246), - ('function_definition -> declaration_specifier_list declarator declaration_list compound_statement','function_definition',4,'p_function_definition','cgrammar.py',1252), - ('function_definition -> declaration_specifier_list declarator compound_statement','function_definition',3,'p_function_definition','cgrammar.py',1253), - ('function_definition -> declarator declaration_list compound_statement','function_definition',3,'p_function_definition','cgrammar.py',1254), - ('function_definition -> declarator compound_statement','function_definition',2,'p_function_definition','cgrammar.py',1255), - ('directive -> define','directive',1,'p_directive','cgrammar.py',1261), - ('directive -> undefine','directive',1,'p_directive','cgrammar.py',1262), - ('directive -> pragma','directive',1,'p_directive','cgrammar.py',1263), - ('define -> PP_DEFINE PP_DEFINE_NAME PP_END_DEFINE','define',3,'p_define','cgrammar.py',1268), - ('define -> PP_DEFINE PP_DEFINE_NAME type_name PP_END_DEFINE','define',4,'p_define','cgrammar.py',1269), - ('define -> PP_DEFINE PP_DEFINE_NAME constant_expression PP_END_DEFINE','define',4,'p_define','cgrammar.py',1270), - ('define -> PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN RPAREN PP_END_DEFINE','define',5,'p_define','cgrammar.py',1271), - ('define -> PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN RPAREN constant_expression PP_END_DEFINE','define',6,'p_define','cgrammar.py',1272), - ('define -> PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN macro_parameter_list RPAREN PP_END_DEFINE','define',6,'p_define','cgrammar.py',1273), - ('define -> PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN macro_parameter_list RPAREN constant_expression PP_END_DEFINE','define',7,'p_define','cgrammar.py',1274), - ('define -> PP_DEFINE error PP_END_DEFINE','define',3,'p_define_error','cgrammar.py',1305), - ('undefine -> PP_UNDEFINE PP_DEFINE_NAME PP_END_DEFINE','undefine',3,'p_undefine','cgrammar.py',1333), - ('macro_parameter_list -> PP_MACRO_PARAM','macro_parameter_list',1,'p_macro_parameter_list','cgrammar.py',1344), - ('macro_parameter_list -> macro_parameter_list COMMA PP_MACRO_PARAM','macro_parameter_list',3,'p_macro_parameter_list','cgrammar.py',1345), - ('pragma -> pragma_pack','pragma',1,'p_pragma','cgrammar.py',1369), - ('pragma_pack -> PRAGMA PRAGMA_PACK LPAREN RPAREN PRAGMA_END','pragma_pack',5,'p_pragma_pack','cgrammar.py',1374), - ('pragma_pack -> PRAGMA PRAGMA_PACK LPAREN constant RPAREN PRAGMA_END','pragma_pack',6,'p_pragma_pack','cgrammar.py',1375), - ('pragma_pack -> PRAGMA PRAGMA_PACK LPAREN pragma_pack_stack_args RPAREN PRAGMA_END','pragma_pack',6,'p_pragma_pack','cgrammar.py',1376), - ('pragma_pack_stack_args -> IDENTIFIER','pragma_pack_stack_args',1,'p_pragma_pack_stack_args','cgrammar.py',1400), - ('pragma_pack_stack_args -> IDENTIFIER COMMA IDENTIFIER','pragma_pack_stack_args',3,'p_pragma_pack_stack_args','cgrammar.py',1401), - ('pragma_pack_stack_args -> IDENTIFIER COMMA IDENTIFIER COMMA constant','pragma_pack_stack_args',5,'p_pragma_pack_stack_args','cgrammar.py',1402), - ('pragma_pack_stack_args -> IDENTIFIER COMMA constant COMMA IDENTIFIER','pragma_pack_stack_args',5,'p_pragma_pack_stack_args','cgrammar.py',1403), - ('pragma_pack_stack_args -> IDENTIFIER COMMA constant','pragma_pack_stack_args',3,'p_pragma_pack_stack_args','cgrammar.py',1404), + ('translation_unit -> ','translation_unit',0,'p_translation_unit','cgrammar.py',124), + ('translation_unit -> translation_unit external_declaration','translation_unit',2,'p_translation_unit','cgrammar.py',125), + ('translation_unit -> translation_unit directive','translation_unit',2,'p_translation_unit','cgrammar.py',126), + ('identifier -> IDENTIFIER','identifier',1,'p_identifier','cgrammar.py',135), + ('identifier -> IDENTIFIER PP_IDENTIFIER_PASTE identifier','identifier',3,'p_identifier','cgrammar.py',136), + ('identifier -> PP_MACRO_PARAM PP_IDENTIFIER_PASTE identifier','identifier',3,'p_identifier','cgrammar.py',137), + ('identifier -> IDENTIFIER PP_IDENTIFIER_PASTE PP_MACRO_PARAM','identifier',3,'p_identifier','cgrammar.py',138), + ('identifier -> PP_MACRO_PARAM PP_IDENTIFIER_PASTE PP_MACRO_PARAM','identifier',3,'p_identifier','cgrammar.py',139), + ('constant -> I_CONST_HEX','constant',1,'p_constant_integer','cgrammar.py',157), + ('constant -> I_CONST_DEC','constant',1,'p_constant_integer','cgrammar.py',158), + ('constant -> I_CONST_OCT','constant',1,'p_constant_integer','cgrammar.py',159), + ('constant -> I_CONST_BIN','constant',1,'p_constant_integer','cgrammar.py',160), + ('constant -> F_CONST_1','constant',1,'p_constant_float','cgrammar.py',173), + ('constant -> F_CONST_2','constant',1,'p_constant_float','cgrammar.py',174), + ('constant -> F_CONST_3','constant',1,'p_constant_float','cgrammar.py',175), + ('constant -> F_CONST_4','constant',1,'p_constant_float','cgrammar.py',176), + ('constant -> F_CONST_5','constant',1,'p_constant_float','cgrammar.py',177), + ('constant -> F_CONST_6','constant',1,'p_constant_float','cgrammar.py',178), + ('constant -> CHARACTER_CONSTANT','constant',1,'p_constant_character','cgrammar.py',184), + ('string_literal -> STRING_LITERAL','string_literal',1,'p_string_literal','cgrammar.py',192), + ('multi_string_literal -> string_literal','multi_string_literal',1,'p_multi_string_literal','cgrammar.py',198), + ('multi_string_literal -> macro_param','multi_string_literal',1,'p_multi_string_literal','cgrammar.py',199), + ('multi_string_literal -> multi_string_literal string_literal','multi_string_literal',2,'p_multi_string_literal','cgrammar.py',200), + ('multi_string_literal -> multi_string_literal macro_param','multi_string_literal',2,'p_multi_string_literal','cgrammar.py',201), + ('macro_param -> PP_MACRO_PARAM','macro_param',1,'p_macro_param','cgrammar.py',212), + ('macro_param -> PP_STRINGIFY PP_MACRO_PARAM','macro_param',2,'p_macro_param','cgrammar.py',213), + ('primary_expression -> identifier','primary_expression',1,'p_primary_expression','cgrammar.py',222), + ('primary_expression -> constant','primary_expression',1,'p_primary_expression','cgrammar.py',223), + ('primary_expression -> multi_string_literal','primary_expression',1,'p_primary_expression','cgrammar.py',224), + ('primary_expression -> LPAREN expression RPAREN','primary_expression',3,'p_primary_expression','cgrammar.py',225), + ('postfix_expression -> primary_expression','postfix_expression',1,'p_postfix_expression','cgrammar.py',234), + ('postfix_expression -> postfix_expression LBRACKET expression RBRACKET','postfix_expression',4,'p_postfix_expression','cgrammar.py',235), + ('postfix_expression -> postfix_expression LPAREN RPAREN','postfix_expression',3,'p_postfix_expression','cgrammar.py',236), + ('postfix_expression -> postfix_expression LPAREN argument_expression_list RPAREN','postfix_expression',4,'p_postfix_expression','cgrammar.py',237), + ('postfix_expression -> postfix_expression PERIOD IDENTIFIER','postfix_expression',3,'p_postfix_expression','cgrammar.py',238), + ('postfix_expression -> postfix_expression PTR_OP IDENTIFIER','postfix_expression',3,'p_postfix_expression','cgrammar.py',239), + ('postfix_expression -> postfix_expression INC_OP','postfix_expression',2,'p_postfix_expression','cgrammar.py',240), + ('postfix_expression -> postfix_expression DEC_OP','postfix_expression',2,'p_postfix_expression','cgrammar.py',241), + ('argument_expression_list -> assignment_expression','argument_expression_list',1,'p_argument_expression_list','cgrammar.py',280), + ('argument_expression_list -> argument_expression_list COMMA assignment_expression','argument_expression_list',3,'p_argument_expression_list','cgrammar.py',281), + ('argument_expression_list -> type_name','argument_expression_list',1,'p_argument_expression_list','cgrammar.py',282), + ('argument_expression_list -> argument_expression_list COMMA type_name','argument_expression_list',3,'p_argument_expression_list','cgrammar.py',283), + ('asm_expression -> __ASM__ volatile_opt LPAREN string_literal RPAREN','asm_expression',5,'p_asm_expression','cgrammar.py',293), + ('asm_expression -> __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list RPAREN','asm_expression',7,'p_asm_expression','cgrammar.py',294), + ('asm_expression -> __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list RPAREN','asm_expression',9,'p_asm_expression','cgrammar.py',295), + ('asm_expression -> __ASM__ volatile_opt LPAREN string_literal COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list COLON str_opt_expr_pair_list RPAREN','asm_expression',11,'p_asm_expression','cgrammar.py',296), + ('str_opt_expr_pair_list -> ','str_opt_expr_pair_list',0,'p_str_opt_expr_pair_list','cgrammar.py',309), + ('str_opt_expr_pair_list -> str_opt_expr_pair','str_opt_expr_pair_list',1,'p_str_opt_expr_pair_list','cgrammar.py',310), + ('str_opt_expr_pair_list -> str_opt_expr_pair_list COMMA str_opt_expr_pair','str_opt_expr_pair_list',3,'p_str_opt_expr_pair_list','cgrammar.py',311), + ('str_opt_expr_pair -> string_literal','str_opt_expr_pair',1,'p_str_opt_expr_pair','cgrammar.py',316), + ('str_opt_expr_pair -> string_literal LPAREN expression RPAREN','str_opt_expr_pair',4,'p_str_opt_expr_pair','cgrammar.py',317), + ('volatile_opt -> ','volatile_opt',0,'p_volatile_opt','cgrammar.py',322), + ('volatile_opt -> VOLATILE','volatile_opt',1,'p_volatile_opt','cgrammar.py',323), + ('unary_expression -> postfix_expression','unary_expression',1,'p_unary_expression','cgrammar.py',340), + ('unary_expression -> INC_OP unary_expression','unary_expression',2,'p_unary_expression','cgrammar.py',341), + ('unary_expression -> DEC_OP unary_expression','unary_expression',2,'p_unary_expression','cgrammar.py',342), + ('unary_expression -> unary_operator cast_expression','unary_expression',2,'p_unary_expression','cgrammar.py',343), + ('unary_expression -> SIZEOF unary_expression','unary_expression',2,'p_unary_expression','cgrammar.py',344), + ('unary_expression -> SIZEOF LPAREN type_name RPAREN','unary_expression',4,'p_unary_expression','cgrammar.py',345), + ('unary_expression -> asm_expression','unary_expression',1,'p_unary_expression','cgrammar.py',346), + ('unary_operator -> AND','unary_operator',1,'p_unary_operator','cgrammar.py',363), + ('unary_operator -> TIMES','unary_operator',1,'p_unary_operator','cgrammar.py',364), + ('unary_operator -> PLUS','unary_operator',1,'p_unary_operator','cgrammar.py',365), + ('unary_operator -> MINUS','unary_operator',1,'p_unary_operator','cgrammar.py',366), + ('unary_operator -> NOT','unary_operator',1,'p_unary_operator','cgrammar.py',367), + ('unary_operator -> LNOT','unary_operator',1,'p_unary_operator','cgrammar.py',368), + ('cast_expression -> unary_expression','cast_expression',1,'p_cast_expression','cgrammar.py',374), + ('cast_expression -> LPAREN type_name RPAREN cast_expression','cast_expression',4,'p_cast_expression','cgrammar.py',375), + ('multiplicative_expression -> cast_expression','multiplicative_expression',1,'p_multiplicative_expression','cgrammar.py',391), + ('multiplicative_expression -> multiplicative_expression TIMES cast_expression','multiplicative_expression',3,'p_multiplicative_expression','cgrammar.py',392), + ('multiplicative_expression -> multiplicative_expression DIVIDE cast_expression','multiplicative_expression',3,'p_multiplicative_expression','cgrammar.py',393), + ('multiplicative_expression -> multiplicative_expression MOD cast_expression','multiplicative_expression',3,'p_multiplicative_expression','cgrammar.py',394), + ('additive_expression -> multiplicative_expression','additive_expression',1,'p_additive_expression','cgrammar.py',410), + ('additive_expression -> additive_expression PLUS multiplicative_expression','additive_expression',3,'p_additive_expression','cgrammar.py',411), + ('additive_expression -> additive_expression MINUS multiplicative_expression','additive_expression',3,'p_additive_expression','cgrammar.py',412), + ('shift_expression -> additive_expression','shift_expression',1,'p_shift_expression','cgrammar.py',428), + ('shift_expression -> shift_expression LEFT_OP additive_expression','shift_expression',3,'p_shift_expression','cgrammar.py',429), + ('shift_expression -> shift_expression RIGHT_OP additive_expression','shift_expression',3,'p_shift_expression','cgrammar.py',430), + ('relational_expression -> shift_expression','relational_expression',1,'p_relational_expression','cgrammar.py',448), + ('relational_expression -> relational_expression LT shift_expression','relational_expression',3,'p_relational_expression','cgrammar.py',449), + ('relational_expression -> relational_expression GT shift_expression','relational_expression',3,'p_relational_expression','cgrammar.py',450), + ('relational_expression -> relational_expression LE_OP shift_expression','relational_expression',3,'p_relational_expression','cgrammar.py',451), + ('relational_expression -> relational_expression GE_OP shift_expression','relational_expression',3,'p_relational_expression','cgrammar.py',452), + ('equality_expression -> relational_expression','equality_expression',1,'p_equality_expression','cgrammar.py',468), + ('equality_expression -> equality_expression EQ_OP relational_expression','equality_expression',3,'p_equality_expression','cgrammar.py',469), + ('equality_expression -> equality_expression NE_OP relational_expression','equality_expression',3,'p_equality_expression','cgrammar.py',470), + ('and_expression -> equality_expression','and_expression',1,'p_and_expression','cgrammar.py',480), + ('and_expression -> and_expression AND equality_expression','and_expression',3,'p_and_expression','cgrammar.py',481), + ('exclusive_or_expression -> and_expression','exclusive_or_expression',1,'p_exclusive_or_expression','cgrammar.py',492), + ('exclusive_or_expression -> exclusive_or_expression XOR and_expression','exclusive_or_expression',3,'p_exclusive_or_expression','cgrammar.py',493), + ('inclusive_or_expression -> exclusive_or_expression','inclusive_or_expression',1,'p_inclusive_or_expression','cgrammar.py',504), + ('inclusive_or_expression -> inclusive_or_expression OR exclusive_or_expression','inclusive_or_expression',3,'p_inclusive_or_expression','cgrammar.py',505), + ('logical_and_expression -> inclusive_or_expression','logical_and_expression',1,'p_logical_and_expression','cgrammar.py',516), + ('logical_and_expression -> logical_and_expression AND_OP inclusive_or_expression','logical_and_expression',3,'p_logical_and_expression','cgrammar.py',517), + ('logical_or_expression -> logical_and_expression','logical_or_expression',1,'p_logical_or_expression','cgrammar.py',528), + ('logical_or_expression -> logical_or_expression OR_OP logical_and_expression','logical_or_expression',3,'p_logical_or_expression','cgrammar.py',529), + ('conditional_expression -> logical_or_expression','conditional_expression',1,'p_conditional_expression','cgrammar.py',540), + ('conditional_expression -> logical_or_expression CONDOP expression COLON conditional_expression','conditional_expression',5,'p_conditional_expression','cgrammar.py',541), + ('assignment_expression -> conditional_expression','assignment_expression',1,'p_assignment_expression','cgrammar.py',564), + ('assignment_expression -> unary_expression assignment_operator assignment_expression','assignment_expression',3,'p_assignment_expression','cgrammar.py',565), + ('assignment_operator -> EQUALS','assignment_operator',1,'p_assignment_operator','cgrammar.py',580), + ('assignment_operator -> MUL_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',581), + ('assignment_operator -> DIV_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',582), + ('assignment_operator -> MOD_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',583), + ('assignment_operator -> ADD_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',584), + ('assignment_operator -> SUB_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',585), + ('assignment_operator -> LEFT_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',586), + ('assignment_operator -> RIGHT_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',587), + ('assignment_operator -> AND_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',588), + ('assignment_operator -> XOR_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',589), + ('assignment_operator -> OR_ASSIGN','assignment_operator',1,'p_assignment_operator','cgrammar.py',590), + ('expression -> assignment_expression','expression',1,'p_expression','cgrammar.py',596), + ('expression -> expression COMMA assignment_expression','expression',3,'p_expression','cgrammar.py',597), + ('constant_expression -> conditional_expression','constant_expression',1,'p_constant_expression','cgrammar.py',604), + ('declaration -> declaration_impl SEMI','declaration',2,'p_declaration','cgrammar.py',610), + ('declaration_impl -> declaration_specifier_list','declaration_impl',1,'p_declaration_impl','cgrammar.py',618), + ('declaration_impl -> declaration_specifier_list init_declarator_list','declaration_impl',2,'p_declaration_impl','cgrammar.py',619), + ('declaration_specifier_list -> gcc_attributes declaration_specifier gcc_attributes','declaration_specifier_list',3,'p_declaration_specifier_list','cgrammar.py',638), + ('declaration_specifier_list -> declaration_specifier_list declaration_specifier gcc_attributes','declaration_specifier_list',3,'p_declaration_specifier_list','cgrammar.py',639), + ('declaration_specifier -> storage_class_specifier','declaration_specifier',1,'p_declaration_specifier','cgrammar.py',652), + ('declaration_specifier -> type_specifier','declaration_specifier',1,'p_declaration_specifier','cgrammar.py',653), + ('declaration_specifier -> type_qualifier','declaration_specifier',1,'p_declaration_specifier','cgrammar.py',654), + ('declaration_specifier -> function_specifier','declaration_specifier',1,'p_declaration_specifier','cgrammar.py',655), + ('init_declarator_list -> init_declarator','init_declarator_list',1,'p_init_declarator_list','cgrammar.py',661), + ('init_declarator_list -> init_declarator_list COMMA init_declarator','init_declarator_list',3,'p_init_declarator_list','cgrammar.py',662), + ('init_declarator -> declarator gcc_attributes','init_declarator',2,'p_init_declarator','cgrammar.py',671), + ('init_declarator -> declarator gcc_attributes EQUALS initializer','init_declarator',4,'p_init_declarator','cgrammar.py',672), + ('storage_class_specifier -> TYPEDEF','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',683), + ('storage_class_specifier -> EXTERN','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',684), + ('storage_class_specifier -> STATIC','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',685), + ('storage_class_specifier -> AUTO','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',686), + ('storage_class_specifier -> REGISTER','storage_class_specifier',1,'p_storage_class_specifier','cgrammar.py',687), + ('type_specifier -> VOID','type_specifier',1,'p_type_specifier','cgrammar.py',693), + ('type_specifier -> _BOOL','type_specifier',1,'p_type_specifier','cgrammar.py',694), + ('type_specifier -> CHAR','type_specifier',1,'p_type_specifier','cgrammar.py',695), + ('type_specifier -> SHORT','type_specifier',1,'p_type_specifier','cgrammar.py',696), + ('type_specifier -> INT','type_specifier',1,'p_type_specifier','cgrammar.py',697), + ('type_specifier -> LONG','type_specifier',1,'p_type_specifier','cgrammar.py',698), + ('type_specifier -> FLOAT','type_specifier',1,'p_type_specifier','cgrammar.py',699), + ('type_specifier -> DOUBLE','type_specifier',1,'p_type_specifier','cgrammar.py',700), + ('type_specifier -> SIGNED','type_specifier',1,'p_type_specifier','cgrammar.py',701), + ('type_specifier -> UNSIGNED','type_specifier',1,'p_type_specifier','cgrammar.py',702), + ('type_specifier -> struct_or_union_specifier','type_specifier',1,'p_type_specifier','cgrammar.py',703), + ('type_specifier -> enum_specifier','type_specifier',1,'p_type_specifier','cgrammar.py',704), + ('type_specifier -> TYPE_NAME','type_specifier',1,'p_type_specifier','cgrammar.py',705), + ('struct_or_union_specifier -> struct_or_union gcc_attributes IDENTIFIER LBRACE member_declaration_list RBRACE','struct_or_union_specifier',6,'p_struct_or_union_specifier','cgrammar.py',714), + ('struct_or_union_specifier -> struct_or_union gcc_attributes TYPE_NAME LBRACE member_declaration_list RBRACE','struct_or_union_specifier',6,'p_struct_or_union_specifier','cgrammar.py',715), + ('struct_or_union_specifier -> struct_or_union gcc_attributes LBRACE member_declaration_list RBRACE','struct_or_union_specifier',5,'p_struct_or_union_specifier','cgrammar.py',716), + ('struct_or_union_specifier -> struct_or_union gcc_attributes IDENTIFIER','struct_or_union_specifier',3,'p_struct_or_union_specifier','cgrammar.py',717), + ('struct_or_union_specifier -> struct_or_union gcc_attributes TYPE_NAME','struct_or_union_specifier',3,'p_struct_or_union_specifier','cgrammar.py',718), + ('struct_or_union -> STRUCT','struct_or_union',1,'p_struct_or_union','cgrammar.py',743), + ('struct_or_union -> UNION','struct_or_union',1,'p_struct_or_union','cgrammar.py',744), + ('gcc_attributes -> ','gcc_attributes',0,'p_gcc_attributes','cgrammar.py',750), + ('gcc_attributes -> gcc_attributes gcc_attribute','gcc_attributes',2,'p_gcc_attributes','cgrammar.py',751), + ('gcc_attribute -> __ATTRIBUTE__ LPAREN LPAREN gcc_attrib_list RPAREN RPAREN','gcc_attribute',6,'p_gcc_attribute','cgrammar.py',762), + ('gcc_attrib_list -> gcc_attrib','gcc_attrib_list',1,'p_gcc_attrib_list','cgrammar.py',769), + ('gcc_attrib_list -> gcc_attrib_list COMMA gcc_attrib','gcc_attrib_list',3,'p_gcc_attrib_list','cgrammar.py',770), + ('gcc_attrib -> ','gcc_attrib',0,'p_gcc_attrib','cgrammar.py',779), + ('gcc_attrib -> IDENTIFIER','gcc_attrib',1,'p_gcc_attrib','cgrammar.py',780), + ('gcc_attrib -> IDENTIFIER LPAREN argument_expression_list RPAREN','gcc_attrib',4,'p_gcc_attrib','cgrammar.py',781), + ('member_declaration_list -> member_declaration','member_declaration_list',1,'p_member_declaration_list','cgrammar.py',794), + ('member_declaration_list -> member_declaration_list member_declaration','member_declaration_list',2,'p_member_declaration_list','cgrammar.py',795), + ('member_declaration -> specifier_qualifier_list member_declarator_list SEMI','member_declaration',3,'p_member_declaration','cgrammar.py',804), + ('member_declaration -> specifier_qualifier_list SEMI','member_declaration',2,'p_member_declaration','cgrammar.py',805), + ('specifier_qualifier_list -> gcc_attributes specifier_qualifier gcc_attributes','specifier_qualifier_list',3,'p_specifier_qualifier_list','cgrammar.py',826), + ('specifier_qualifier_list -> specifier_qualifier_list specifier_qualifier gcc_attributes','specifier_qualifier_list',3,'p_specifier_qualifier_list','cgrammar.py',827), + ('specifier_qualifier -> type_specifier','specifier_qualifier',1,'p_specifier_qualifier','cgrammar.py',836), + ('specifier_qualifier -> type_qualifier','specifier_qualifier',1,'p_specifier_qualifier','cgrammar.py',837), + ('member_declarator_list -> member_declarator','member_declarator_list',1,'p_member_declarator_list','cgrammar.py',843), + ('member_declarator_list -> member_declarator_list COMMA member_declarator','member_declarator_list',3,'p_member_declarator_list','cgrammar.py',844), + ('member_declarator -> declarator gcc_attributes','member_declarator',2,'p_member_declarator','cgrammar.py',853), + ('member_declarator -> COLON constant_expression gcc_attributes','member_declarator',3,'p_member_declarator','cgrammar.py',854), + ('member_declarator -> declarator COLON constant_expression gcc_attributes','member_declarator',4,'p_member_declarator','cgrammar.py',855), + ('enum_specifier -> ENUM LBRACE enumerator_list RBRACE','enum_specifier',4,'p_enum_specifier','cgrammar.py',870), + ('enum_specifier -> ENUM IDENTIFIER LBRACE enumerator_list RBRACE','enum_specifier',5,'p_enum_specifier','cgrammar.py',871), + ('enum_specifier -> ENUM IDENTIFIER','enum_specifier',2,'p_enum_specifier','cgrammar.py',872), + ('enumerator_list -> enumerator_list_iso','enumerator_list',1,'p_enumerator_list','cgrammar.py',886), + ('enumerator_list -> enumerator_list_iso COMMA','enumerator_list',2,'p_enumerator_list','cgrammar.py',887), + ('enumerator_list_iso -> enumerator','enumerator_list_iso',1,'p_enumerator_list_iso','cgrammar.py',895), + ('enumerator_list_iso -> enumerator_list_iso COMMA enumerator','enumerator_list_iso',3,'p_enumerator_list_iso','cgrammar.py',896), + ('enumerator -> IDENTIFIER','enumerator',1,'p_enumerator','cgrammar.py',905), + ('enumerator -> IDENTIFIER EQUALS constant_expression','enumerator',3,'p_enumerator','cgrammar.py',906), + ('type_qualifier -> CONST','type_qualifier',1,'p_type_qualifier','cgrammar.py',915), + ('type_qualifier -> VOLATILE','type_qualifier',1,'p_type_qualifier','cgrammar.py',916), + ('type_qualifier -> RESTRICT','type_qualifier',1,'p_type_qualifier','cgrammar.py',917), + ('function_specifier -> INLINE','function_specifier',1,'p_function_specifier','cgrammar.py',923), + ('function_specifier -> _NORETURN','function_specifier',1,'p_function_specifier','cgrammar.py',924), + ('declarator -> pointer direct_declarator','declarator',2,'p_declarator','cgrammar.py',929), + ('declarator -> direct_declarator','declarator',1,'p_declarator','cgrammar.py',930), + ('direct_declarator -> IDENTIFIER','direct_declarator',1,'p_direct_declarator','cgrammar.py',944), + ('direct_declarator -> LPAREN gcc_attributes declarator RPAREN','direct_declarator',4,'p_direct_declarator','cgrammar.py',945), + ('direct_declarator -> direct_declarator LBRACKET constant_expression RBRACKET','direct_declarator',4,'p_direct_declarator','cgrammar.py',946), + ('direct_declarator -> direct_declarator LBRACKET RBRACKET','direct_declarator',3,'p_direct_declarator','cgrammar.py',947), + ('direct_declarator -> direct_declarator LPAREN parameter_type_list RPAREN','direct_declarator',4,'p_direct_declarator','cgrammar.py',948), + ('direct_declarator -> direct_declarator LPAREN identifier_list RPAREN','direct_declarator',4,'p_direct_declarator','cgrammar.py',949), + ('direct_declarator -> direct_declarator LPAREN RPAREN','direct_declarator',3,'p_direct_declarator','cgrammar.py',950), + ('pointer -> TIMES','pointer',1,'p_pointer','cgrammar.py',980), + ('pointer -> TIMES type_qualifier_list','pointer',2,'p_pointer','cgrammar.py',981), + ('pointer -> TIMES pointer','pointer',2,'p_pointer','cgrammar.py',982), + ('pointer -> TIMES type_qualifier_list pointer','pointer',3,'p_pointer','cgrammar.py',983), + ('type_qualifier_list -> type_qualifier','type_qualifier_list',1,'p_type_qualifier_list','cgrammar.py',1005), + ('type_qualifier_list -> gcc_attribute','type_qualifier_list',1,'p_type_qualifier_list','cgrammar.py',1006), + ('type_qualifier_list -> type_qualifier_list type_qualifier','type_qualifier_list',2,'p_type_qualifier_list','cgrammar.py',1007), + ('type_qualifier_list -> type_qualifier_list gcc_attribute','type_qualifier_list',2,'p_type_qualifier_list','cgrammar.py',1008), + ('parameter_type_list -> parameter_list','parameter_type_list',1,'p_parameter_type_list','cgrammar.py',1017), + ('parameter_type_list -> parameter_list COMMA ELLIPSIS','parameter_type_list',3,'p_parameter_type_list','cgrammar.py',1018), + ('parameter_list -> parameter_declaration','parameter_list',1,'p_parameter_list','cgrammar.py',1027), + ('parameter_list -> parameter_list COMMA parameter_declaration','parameter_list',3,'p_parameter_list','cgrammar.py',1028), + ('parameter_declaration -> declaration_specifier_list declarator gcc_attributes','parameter_declaration',3,'p_parameter_declaration','cgrammar.py',1037), + ('parameter_declaration -> declaration_specifier_list abstract_declarator','parameter_declaration',2,'p_parameter_declaration','cgrammar.py',1038), + ('parameter_declaration -> declaration_specifier_list','parameter_declaration',1,'p_parameter_declaration','cgrammar.py',1039), + ('identifier_list -> IDENTIFIER','identifier_list',1,'p_identifier_list','cgrammar.py',1055), + ('identifier_list -> identifier_list COMMA IDENTIFIER','identifier_list',3,'p_identifier_list','cgrammar.py',1056), + ('type_name -> specifier_qualifier_list','type_name',1,'p_type_name','cgrammar.py',1069), + ('type_name -> specifier_qualifier_list abstract_declarator','type_name',2,'p_type_name','cgrammar.py',1070), + ('abstract_declarator -> pointer','abstract_declarator',1,'p_abstract_declarator','cgrammar.py',1086), + ('abstract_declarator -> direct_abstract_declarator gcc_attributes','abstract_declarator',2,'p_abstract_declarator','cgrammar.py',1087), + ('abstract_declarator -> pointer direct_abstract_declarator gcc_attributes','abstract_declarator',3,'p_abstract_declarator','cgrammar.py',1088), + ('direct_abstract_declarator -> LPAREN gcc_attributes abstract_declarator RPAREN','direct_abstract_declarator',4,'p_direct_abstract_declarator','cgrammar.py',1115), + ('direct_abstract_declarator -> LBRACKET RBRACKET','direct_abstract_declarator',2,'p_direct_abstract_declarator','cgrammar.py',1116), + ('direct_abstract_declarator -> LBRACKET constant_expression RBRACKET','direct_abstract_declarator',3,'p_direct_abstract_declarator','cgrammar.py',1117), + ('direct_abstract_declarator -> direct_abstract_declarator LBRACKET RBRACKET','direct_abstract_declarator',3,'p_direct_abstract_declarator','cgrammar.py',1118), + ('direct_abstract_declarator -> direct_abstract_declarator LBRACKET constant_expression RBRACKET','direct_abstract_declarator',4,'p_direct_abstract_declarator','cgrammar.py',1119), + ('direct_abstract_declarator -> LPAREN RPAREN','direct_abstract_declarator',2,'p_direct_abstract_declarator','cgrammar.py',1120), + ('direct_abstract_declarator -> LPAREN parameter_type_list RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator','cgrammar.py',1121), + ('direct_abstract_declarator -> direct_abstract_declarator LPAREN RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator','cgrammar.py',1122), + ('direct_abstract_declarator -> direct_abstract_declarator LPAREN parameter_type_list RPAREN','direct_abstract_declarator',4,'p_direct_abstract_declarator','cgrammar.py',1123), + ('initializer -> assignment_expression','initializer',1,'p_initializer','cgrammar.py',1162), + ('initializer -> LBRACE initializer_list RBRACE','initializer',3,'p_initializer','cgrammar.py',1163), + ('initializer -> LBRACE initializer_list COMMA RBRACE','initializer',4,'p_initializer','cgrammar.py',1164), + ('initializer_list -> initializer','initializer_list',1,'p_initializer_list','cgrammar.py',1169), + ('initializer_list -> initializer_list COMMA initializer','initializer_list',3,'p_initializer_list','cgrammar.py',1170), + ('statement -> labeled_statement','statement',1,'p_statement','cgrammar.py',1175), + ('statement -> compound_statement','statement',1,'p_statement','cgrammar.py',1176), + ('statement -> expression_statement','statement',1,'p_statement','cgrammar.py',1177), + ('statement -> selection_statement','statement',1,'p_statement','cgrammar.py',1178), + ('statement -> iteration_statement','statement',1,'p_statement','cgrammar.py',1179), + ('statement -> jump_statement','statement',1,'p_statement','cgrammar.py',1180), + ('labeled_statement -> IDENTIFIER COLON statement','labeled_statement',3,'p_labeled_statement','cgrammar.py',1185), + ('labeled_statement -> CASE constant_expression COLON statement','labeled_statement',4,'p_labeled_statement','cgrammar.py',1186), + ('labeled_statement -> DEFAULT COLON statement','labeled_statement',3,'p_labeled_statement','cgrammar.py',1187), + ('compound_statement -> LBRACE RBRACE','compound_statement',2,'p_compound_statement','cgrammar.py',1192), + ('compound_statement -> LBRACE statement_list RBRACE','compound_statement',3,'p_compound_statement','cgrammar.py',1193), + ('compound_statement -> LBRACE declaration_list RBRACE','compound_statement',3,'p_compound_statement','cgrammar.py',1194), + ('compound_statement -> LBRACE declaration_list statement_list RBRACE','compound_statement',4,'p_compound_statement','cgrammar.py',1195), + ('compound_statement -> LBRACE error RBRACE','compound_statement',3,'p_compound_statement_error','cgrammar.py',1200), + ('declaration_list -> declaration','declaration_list',1,'p_declaration_list','cgrammar.py',1206), + ('declaration_list -> declaration_list declaration','declaration_list',2,'p_declaration_list','cgrammar.py',1207), + ('statement_list -> statement','statement_list',1,'p_statement_list','cgrammar.py',1212), + ('statement_list -> statement_list statement','statement_list',2,'p_statement_list','cgrammar.py',1213), + ('expression_statement -> SEMI','expression_statement',1,'p_expression_statement','cgrammar.py',1218), + ('expression_statement -> expression SEMI','expression_statement',2,'p_expression_statement','cgrammar.py',1219), + ('expression_statement -> error SEMI','expression_statement',2,'p_expression_statement_error','cgrammar.py',1224), + ('selection_statement -> IF LPAREN expression RPAREN statement','selection_statement',5,'p_selection_statement','cgrammar.py',1230), + ('selection_statement -> IF LPAREN expression RPAREN statement ELSE statement','selection_statement',7,'p_selection_statement','cgrammar.py',1231), + ('selection_statement -> SWITCH LPAREN expression RPAREN statement','selection_statement',5,'p_selection_statement','cgrammar.py',1232), + ('iteration_statement -> WHILE LPAREN expression RPAREN statement','iteration_statement',5,'p_iteration_statement','cgrammar.py',1237), + ('iteration_statement -> DO statement WHILE LPAREN expression RPAREN SEMI','iteration_statement',7,'p_iteration_statement','cgrammar.py',1238), + ('iteration_statement -> FOR LPAREN expression_statement expression_statement RPAREN statement','iteration_statement',6,'p_iteration_statement','cgrammar.py',1239), + ('iteration_statement -> FOR LPAREN expression_statement expression_statement expression RPAREN statement','iteration_statement',7,'p_iteration_statement','cgrammar.py',1240), + ('jump_statement -> GOTO IDENTIFIER SEMI','jump_statement',3,'p_jump_statement','cgrammar.py',1245), + ('jump_statement -> CONTINUE SEMI','jump_statement',2,'p_jump_statement','cgrammar.py',1246), + ('jump_statement -> BREAK SEMI','jump_statement',2,'p_jump_statement','cgrammar.py',1247), + ('jump_statement -> RETURN SEMI','jump_statement',2,'p_jump_statement','cgrammar.py',1248), + ('jump_statement -> RETURN expression SEMI','jump_statement',3,'p_jump_statement','cgrammar.py',1249), + ('external_declaration -> declaration','external_declaration',1,'p_external_declaration','cgrammar.py',1254), + ('external_declaration -> function_definition','external_declaration',1,'p_external_declaration','cgrammar.py',1255), + ('function_definition -> declaration_specifier_list declarator declaration_list compound_statement','function_definition',4,'p_function_definition','cgrammar.py',1261), + ('function_definition -> declaration_specifier_list declarator compound_statement','function_definition',3,'p_function_definition','cgrammar.py',1262), + ('function_definition -> declarator declaration_list compound_statement','function_definition',3,'p_function_definition','cgrammar.py',1263), + ('function_definition -> declarator compound_statement','function_definition',2,'p_function_definition','cgrammar.py',1264), + ('directive -> define','directive',1,'p_directive','cgrammar.py',1270), + ('directive -> undefine','directive',1,'p_directive','cgrammar.py',1271), + ('directive -> pragma','directive',1,'p_directive','cgrammar.py',1272), + ('define -> PP_DEFINE PP_DEFINE_NAME PP_END_DEFINE','define',3,'p_define','cgrammar.py',1277), + ('define -> PP_DEFINE PP_DEFINE_NAME type_name PP_END_DEFINE','define',4,'p_define','cgrammar.py',1278), + ('define -> PP_DEFINE PP_DEFINE_NAME constant_expression PP_END_DEFINE','define',4,'p_define','cgrammar.py',1279), + ('define -> PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN RPAREN PP_END_DEFINE','define',5,'p_define','cgrammar.py',1280), + ('define -> PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN RPAREN constant_expression PP_END_DEFINE','define',6,'p_define','cgrammar.py',1281), + ('define -> PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN macro_parameter_list RPAREN PP_END_DEFINE','define',6,'p_define','cgrammar.py',1282), + ('define -> PP_DEFINE PP_DEFINE_MACRO_NAME LPAREN macro_parameter_list RPAREN constant_expression PP_END_DEFINE','define',7,'p_define','cgrammar.py',1283), + ('define -> PP_DEFINE error PP_END_DEFINE','define',3,'p_define_error','cgrammar.py',1314), + ('undefine -> PP_UNDEFINE PP_DEFINE_NAME PP_END_DEFINE','undefine',3,'p_undefine','cgrammar.py',1342), + ('macro_parameter_list -> PP_MACRO_PARAM','macro_parameter_list',1,'p_macro_parameter_list','cgrammar.py',1353), + ('macro_parameter_list -> macro_parameter_list COMMA PP_MACRO_PARAM','macro_parameter_list',3,'p_macro_parameter_list','cgrammar.py',1354), + ('pragma -> pragma_pack','pragma',1,'p_pragma','cgrammar.py',1378), + ('pragma -> PRAGMA pragma_directive_list PRAGMA_END','pragma',3,'p_pragma','cgrammar.py',1379), + ('pragma_pack -> PRAGMA PRAGMA_PACK LPAREN RPAREN PRAGMA_END','pragma_pack',5,'p_pragma_pack','cgrammar.py',1384), + ('pragma_pack -> PRAGMA PRAGMA_PACK LPAREN constant RPAREN PRAGMA_END','pragma_pack',6,'p_pragma_pack','cgrammar.py',1385), + ('pragma_pack -> PRAGMA PRAGMA_PACK LPAREN pragma_pack_stack_args RPAREN PRAGMA_END','pragma_pack',6,'p_pragma_pack','cgrammar.py',1386), + ('pragma_pack_stack_args -> IDENTIFIER','pragma_pack_stack_args',1,'p_pragma_pack_stack_args','cgrammar.py',1410), + ('pragma_pack_stack_args -> IDENTIFIER COMMA IDENTIFIER','pragma_pack_stack_args',3,'p_pragma_pack_stack_args','cgrammar.py',1411), + ('pragma_pack_stack_args -> IDENTIFIER COMMA IDENTIFIER COMMA constant','pragma_pack_stack_args',5,'p_pragma_pack_stack_args','cgrammar.py',1412), + ('pragma_pack_stack_args -> IDENTIFIER COMMA constant COMMA IDENTIFIER','pragma_pack_stack_args',5,'p_pragma_pack_stack_args','cgrammar.py',1413), + ('pragma_pack_stack_args -> IDENTIFIER COMMA constant','pragma_pack_stack_args',3,'p_pragma_pack_stack_args','cgrammar.py',1414), + ('pragma_directive_list -> pragma_directive','pragma_directive_list',1,'p_pragma_directive_list','cgrammar.py',1434), + ('pragma_directive_list -> pragma_directive_list pragma_directive','pragma_directive_list',2,'p_pragma_directive_list','cgrammar.py',1435), + ('pragma_directive -> IDENTIFIER','pragma_directive',1,'p_pragma_directive','cgrammar.py',1444), + ('pragma_directive -> string_literal','pragma_directive',1,'p_pragma_directive','cgrammar.py',1445), ] diff --git a/python/libgrass_interface_generator/ctypesgen/parser/preprocessor.py b/python/libgrass_interface_generator/ctypesgen/parser/preprocessor.py index 3c1e533c956..38898874b09 100755 --- a/python/libgrass_interface_generator/ctypesgen/parser/preprocessor.py +++ b/python/libgrass_interface_generator/ctypesgen/parser/preprocessor.py @@ -57,8 +57,6 @@ def token(self): class PreprocessorParser(object): def __init__(self, options, cparser): self.defines = [ - "inline=", - "__inline__=", "__extension__=", "__const=const", "__asm__(x)=", @@ -70,9 +68,6 @@ def __init__(self, options, cparser): # errors in the macOS standard headers. if IS_MAC: self.defines += [ - "__uint16_t=uint16_t", - "__uint32_t=uint32_t", - "__uint64_t=uint64_t", "_Nullable=", "_Nonnull=", ] diff --git a/python/libgrass_interface_generator/ctypesgen/version.py b/python/libgrass_interface_generator/ctypesgen/version.py index fd2728a39ec..27e370ae991 100755 --- a/python/libgrass_interface_generator/ctypesgen/version.py +++ b/python/libgrass_interface_generator/ctypesgen/version.py @@ -37,13 +37,14 @@ def version(): out, err = p.communicate() if p.returncode: raise RuntimeError("no version defined?") - return out.strip().decode() + git_tag = out.strip().decode() + return f"{DEFAULT_PREFIX}-{git_tag}" except Exception: # failover is to try VERSION_FILE instead try: - return read_file_version() + return f"{DEFAULT_PREFIX}-{read_file_version()}" except Exception: - return DEFAULT_PREFIX + "-0.0.0" + return f"{DEFAULT_PREFIX}-0.0.0" def version_number(): @@ -72,11 +73,11 @@ def write_version_file(v=None): import argparse p = argparse.ArgumentParser() - p.add_argument("--save", action="store_true", help="Store version to " + VERSION_FILE) + p.add_argument("--save", action="store_true", help=f"Store version to {VERSION_FILE}") p.add_argument( "--read-file-version", action="store_true", - help="Read the version stored in " + VERSION_FILE, + help=f"Read the version stored in {VERSION_FILE}", ) args = p.parse_args() From b4a5c746056a398ea6183b59edca1e415da5f6e6 Mon Sep 17 00:00:00 2001 From: Stefan Blumentrath Date: Fri, 28 Oct 2022 16:49:06 +0200 Subject: [PATCH 058/123] g.extension: add tests for download from various sources (#1158) * add download test (skipped by default) * skip by default * correct testfile name in header * remove unused variables * add test for bundeled modules * address review * reset branch * replace importlib * apply more recent black * address comments from code review * fix test failure, remove unnecessary, unstable test * skip tests that cannot run on MS Windows * add reason for skiping tests * Update scripts/g.extension/testsuite/test_addons_download.py Co-authored-by: Vaclav Petras * address more code review * add docstring * test addon start and adjustments for MS Windows * fixes for MS Windows Co-authored-by: ninsbl Co-authored-by: Vaclav Petras --- .../testsuite/test_addons_download.py | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 scripts/g.extension/testsuite/test_addons_download.py diff --git a/scripts/g.extension/testsuite/test_addons_download.py b/scripts/g.extension/testsuite/test_addons_download.py new file mode 100644 index 00000000000..d3b08541ed1 --- /dev/null +++ b/scripts/g.extension/testsuite/test_addons_download.py @@ -0,0 +1,160 @@ +""" +TEST: test_addons_download.py + +AUTHOR(S): Stefan Blumentrath =v2). Read the file COPYING that comes with GRASS + for details. +""" + +import sys +import unittest + +from pathlib import Path + +from grass.gunittest.case import TestCase +from grass.gunittest.main import test +from grass.gunittest.utils import silent_rmtree + +ms_windows = sys.platform == "win32" or sys.platform == "cygwin" + + +class TestModuleDownloadFromDifferentSources(TestCase): + """Tests if addons are downloaded and installed successfully + by checking that respective files are present in the prefix directory + and that the addon starts (help is printed) + Based on test_addons_modules.py bym Vaclav Petras + """ + + # MS Windows install function requires absolute paths + install_prefix = Path("gextension_test_install_path").absolute() + + files = [ + install_prefix / "scripts" / "r.example.plus", + install_prefix / "docs" / "html" / "r.example.plus.html", + ] + + def setUp(self): + """Make sure we are not dealing with some old files""" + if self.install_prefix.exists(): + files = list(path.name for path in self.install_prefix.iterdir()) + if files: + RuntimeError( + f"Install prefix path '{self.install_prefix}' \ + contains files {','.join(files)}" + ) + + def tearDown(self): + """Remove created files""" + silent_rmtree(str(self.install_prefix)) + + @unittest.skipIf(ms_windows, "currently not supported on MS Windows") + def test_github_install(self): + """Test installing extension from github""" + + # Modules with non-standard branch would be good for testing... + self.assertModule( + "g.extension", + extension="r.example.plus", + url="https://github.com/wenzeslaus/r.example.plus", + prefix=str(self.install_prefix), + ) + + for file in self.files: + self.assertFileExists(file) + if file.suffix != ".html": + self.assertModule(str(file), help=True) + + @unittest.skipIf(ms_windows, "currently not supported on MS Windows") + def test_gitlab_install(self): + """Test installing extension from gitlab""" + self.assertModule( + "g.extension", + extension="r.example.plus", + url="https://gitlab.com/vpetras/r.example.plus", + prefix=str(self.install_prefix), + ) + + for file in self.files: + self.assertFileExists(file) + if file.suffix != ".html": + self.assertModule(str(file), help=True) + + @unittest.skipIf(ms_windows, "currently not supported on MS Windows") + def test_bitbucket_install(self): + """Test installing extension from bitbucket""" + files = [ + self.install_prefix / "scripts" / "r.sim.stats", + self.install_prefix / "docs" / "html" / "r.sim.stats.html", + ] + self.assertModule( + "g.extension", + extension="r.sim.stats", + url="https://bitbucket.org/lrntct/r.sim.stats", + prefix=str(self.install_prefix), + ) + + for file in files: + self.assertFileExists(file) + if file.suffix != ".html": + self.assertModule(str(file), help=True) + + def test_github_install_official(self): + """Test installing C-extension from official addons repository""" + files = [ + self.install_prefix / "docs" / "html" / "r.gdd.html", + ] + if ms_windows: + files.append(self.install_prefix / "bin" / "r.gdd.exe") + else: + files.append(self.install_prefix / "bin" / "r.gdd") + + self.assertModule( + "g.extension", extension="r.gdd", prefix=str(self.install_prefix) + ) + + for file in files: + self.assertFileExists(file) + if file.suffix != ".html": + self.assertModule(str(file), help=True) + + def test_github_install_official_multimodule(self): + """Test installing multi-module extension from official addons repository""" + files = [ + self.install_prefix / "docs" / "html" / "i.sentinel.parallel.download.html", + self.install_prefix / "docs" / "html" / "i.sentinel.import.html", + ] + if ms_windows: + files.extend( + [ + self.install_prefix / "scripts" / "i.sentinel.parallel.download.py", + self.install_prefix / "scripts" / "i.sentinel.import.py", + self.install_prefix / "bin" / "i.sentinel.parallel.download.bat", + self.install_prefix / "bin" / "i.sentinel.import.bat", + ] + ) + else: + files.extend( + [ + self.install_prefix / "scripts" / "i.sentinel.parallel.download", + self.install_prefix / "scripts" / "i.sentinel.import", + ] + ) + + self.assertModule( + "g.extension", extension="i.sentinel", prefix=str(self.install_prefix) + ) + + for file in files: + self.assertFileExists(file) + if file.suffix != ".html" and file.suffix != ".py": + self.assertModule(str(file), help=True) + + +if __name__ == "__main__": + test() From e23de8d2706c59bd0900e3c0fd5bd0ff4db423fe Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Mon, 31 Oct 2022 19:38:42 +0100 Subject: [PATCH 059/123] wxGUI: fix display of all single window mode main toolbar tools (#2617) On the MS Windows and macOS platform. --- gui/wxpython/gui_core/toolbars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/wxpython/gui_core/toolbars.py b/gui/wxpython/gui_core/toolbars.py index 8800e4c7bd6..c88c0b0aab5 100644 --- a/gui/wxpython/gui_core/toolbars.py +++ b/gui/wxpython/gui_core/toolbars.py @@ -386,7 +386,7 @@ def __init__( parent, toolSwitcher=None, style=wx.NO_BORDER | wx.TB_HORIZONTAL, - agwStyle=aui.AUI_TB_PLAIN_BACKGROUND, + agwStyle=aui.AUI_TB_PLAIN_BACKGROUND | aui.AUI_TB_GRIPPER, ): self.parent = parent super().__init__( From 7022707b2ad36a87ead87d7127dd6835da6d9df8 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Thu, 3 Nov 2022 05:54:40 +0100 Subject: [PATCH 060/123] wxGUI: fix setting of user defined window position and size for single window mode (#2619) --- gui/wxpython/main_window/frame.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index e09622957ef..00f8a4dd0a4 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -189,7 +189,8 @@ def show_menu_errors(messages): except Exception: pass self.Layout() - self.Fit() + if w <= globalvar.GM_WINDOW_SIZE[0] or h <= globalvar.GM_WINDOW_SIZE[1]: + self.Fit() else: self.Layout() self.Fit() From 245a166efc1ff6b75ea77e62c376247461f69768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Thu, 3 Nov 2022 19:54:51 +0200 Subject: [PATCH 061/123] r.kappa: Fix failures, garbage output, fallback to category values (#2573) * use raster category values in matrix output if labels are not present * print NAs also for the first category Although original code lacks any explanation why NA should not be printed for the first raster category, I do suspect it stems from idea that the first cat is 0 and before proper NULL support 0 was "no data" value. * r.kappa: fix incorrect memory access and improve edge case handling pii, pi, pj and pii all are arrays with size of ncat thus when nstats < ncat it was causing out of bounds reads and writes. A resulting segfault was reported in: https://trac.osgeo.org/grass/ticket/3978 * tests for most of functionality --- raster/r.kappa/calc_kappa.c | 48 ++-- raster/r.kappa/prt2csv_mat.c | 10 +- raster/r.kappa/testsuite/data/class_1.ascii | 14 + raster/r.kappa/testsuite/data/class_2.ascii | 14 + raster/r.kappa/testsuite/data/ref_1.ascii | 14 + raster/r.kappa/testsuite/data/ref_2.ascii | 14 + raster/r.kappa/testsuite/test_r_kappa.py | 296 ++++++++++++++++++++ 7 files changed, 390 insertions(+), 20 deletions(-) create mode 100644 raster/r.kappa/testsuite/data/class_1.ascii create mode 100644 raster/r.kappa/testsuite/data/class_2.ascii create mode 100644 raster/r.kappa/testsuite/data/ref_1.ascii create mode 100644 raster/r.kappa/testsuite/data/ref_2.ascii create mode 100644 raster/r.kappa/testsuite/test_r_kappa.py diff --git a/raster/r.kappa/calc_kappa.c b/raster/r.kappa/calc_kappa.c index 431a718954b..ba4d15943c2 100644 --- a/raster/r.kappa/calc_kappa.c +++ b/raster/r.kappa/calc_kappa.c @@ -8,6 +8,7 @@ void calc_kappa(void) { int i, j; + int a_i, b_i; int s, l; int nl; size_t ns; @@ -37,10 +38,10 @@ void calc_kappa(void) total = count_sum(&s, l); /* calculate the parameters of the kappa-calculation */ - pi = (double *)G_calloc(ns, sizeof(double)); - pj = (double *)G_calloc(ns, sizeof(double)); - pii = (double *)G_calloc(ns, sizeof(double)); - kpp = (double *)G_calloc(ns, sizeof(double)); + pi = (double *)G_calloc(ncat, sizeof(double)); + pj = (double *)G_calloc(ncat, sizeof(double)); + pii = (double *)G_calloc(ncat, sizeof(double)); + kpp = (double *)G_calloc(ncat, sizeof(double)); for (i = 0; i < ncat; i++) { for (j = 0; j < ns; j++) { @@ -65,31 +66,46 @@ void calc_kappa(void) pC += pi[i] * pj[i]; } - for (i = 0; i < ncat; i++) - if ((pi[i] == 0) || (pj[i] == 0)) + for (i = 0; i < ncat; i++) { + if (pi[i] == 0) kpp[i] = -999; else kpp[i] = (pii[i] - pi[i] * pj[i]) / (pi[i] - pi[i] * pj[i]); + } /* print out the comission and omission accuracy, and conditional kappa */ fprintf(fd, "\nCats\t%% Comission\t%% Omission\tEstimated Kappa\n"); - for (i = 0; i < ncat; i++) - if ((kpp[i] == -999) && (i != 0)) - fprintf(fd, "%ld\tNA\t\tNA\t\tNA\n", rlst[i]); + for (i = 0; i < ncat; i++) { + fprintf(fd, "%ld\t", rlst[i]); + if (pi[i] == 0) + fprintf(fd, "NA\t\t"); + else + fprintf(fd, "%f\t", 100 * (1 - pii[i] / pi[i])); + if (pj[i] == 0) + fprintf(fd, "NA\t\t"); else - fprintf(fd, "%ld\t%f\t%f\t%f\n", - rlst[i], 100 * (1 - pii[i] / pi[i]), - 100 * (1 - pii[i] / pj[i]), kpp[i]); + fprintf(fd, "%f\t", 100 * (1 - pii[i] / pj[i])); + if (kpp[i] == -999) + fprintf(fd, "NA\n"); + else + fprintf(fd, "%f\n", kpp[i]); + } fprintf(fd, "\n"); for (i = 0; i < ncat; i++) { inter1 += pii[i] * pow(((1 - pC) - (1 - p0) * (pi[i] + pj[i])), 2.); } + for (j = 0; j < ns; j++) { - if (Gstats[j].cats[0] != Gstats[j].cats[1]) - inter2 += Gstats[j].count * - pow((pi[Gstats[j].cats[0] - 1] + pj[Gstats[j].cats[1] - 1]), - 2.) / total; + if (Gstats[j].cats[0] != Gstats[j].cats[1]) { + for (i = 0; i < ncat; i++) { + if (Gstats[j].cats[0] == rlst[i]) + a_i = i; + if (Gstats[j].cats[1] == rlst[i]) + b_i = i; + } + inter2 += Gstats[j].count * pow((pi[a_i] + pj[b_i]), 2.) / total; + } } kp = (p0 - pC) / (1 - pC); vkp = (inter1 + pow((1 - p0), 2.) * inter2 - diff --git a/raster/r.kappa/prt2csv_mat.c b/raster/r.kappa/prt2csv_mat.c index f870f8a1617..0ac370fc581 100644 --- a/raster/r.kappa/prt2csv_mat.c +++ b/raster/r.kappa/prt2csv_mat.c @@ -97,8 +97,9 @@ void prn2csv_error_mat(int out_cols, int hdr) if (cl) G_strip(cl); if (cl == NULL || *cl == 0) - cl = "NULL"; - fprintf(fd, "%s\t", cl); + fprintf(fd, "%ld\t", cats[j]); + else + fprintf(fd, "%s\t", cl); } /*for (cndx = first_col; cndx < last_col; cndx++) */ /* fprintf(fd, "%ld\t", rlst[cndx]); */ @@ -112,8 +113,9 @@ void prn2csv_error_mat(int out_cols, int hdr) if (cl) G_strip(cl); if (cl == NULL || *cl == 0) - cl = "NULL"; - fprintf(fd, "%s\t", cl); + fprintf(fd, "%ld\t", cats[rndx]); + else + fprintf(fd, "%s\t", cl); /* entries */ for (cndx = first_col; cndx < last_col; cndx++) { thisone = (ncat * rndx) + cndx; diff --git a/raster/r.kappa/testsuite/data/class_1.ascii b/raster/r.kappa/testsuite/data/class_1.ascii new file mode 100644 index 00000000000..b548d1d634d --- /dev/null +++ b/raster/r.kappa/testsuite/data/class_1.ascii @@ -0,0 +1,14 @@ +north: 5 +south: 0 +east: 5 +west: 0 +rows: 5 +cols: 5 +null: n +type: int + +1 n 3 3 4 +5 3 1 4 n +n 1 3 6 6 +6 n 6 1 3 +4 4 4 4 3 diff --git a/raster/r.kappa/testsuite/data/class_2.ascii b/raster/r.kappa/testsuite/data/class_2.ascii new file mode 100644 index 00000000000..15b47aedbc8 --- /dev/null +++ b/raster/r.kappa/testsuite/data/class_2.ascii @@ -0,0 +1,14 @@ +north: 5 +south: 0 +east: 5 +west: 0 +rows: 5 +cols: 5 +null: n +type: int + +9 9 9 9 9 +9 9 9 9 9 +9 9 9 9 9 +9 9 9 9 9 +9 9 9 9 9 diff --git a/raster/r.kappa/testsuite/data/ref_1.ascii b/raster/r.kappa/testsuite/data/ref_1.ascii new file mode 100644 index 00000000000..320571cbe1f --- /dev/null +++ b/raster/r.kappa/testsuite/data/ref_1.ascii @@ -0,0 +1,14 @@ +north: 5 +south: 0 +east: 5 +west: 0 +rows: 5 +cols: 5 +null: n +type: int + +1 3 n 3 6 +5 3 1 n n +n 1 2 2 2 +6 n 6 1 3 +1 1 1 n 3 diff --git a/raster/r.kappa/testsuite/data/ref_2.ascii b/raster/r.kappa/testsuite/data/ref_2.ascii new file mode 100644 index 00000000000..eceb8ac4a5d --- /dev/null +++ b/raster/r.kappa/testsuite/data/ref_2.ascii @@ -0,0 +1,14 @@ +north: 5 +south: 0 +east: 5 +west: 0 +rows: 5 +cols: 5 +null: n +type: int + +0 1 2 1 0 +1 2 3 2 1 +2 3 4 3 2 +1 2 3 2 1 +0 1 2 1 0 diff --git a/raster/r.kappa/testsuite/test_r_kappa.py b/raster/r.kappa/testsuite/test_r_kappa.py new file mode 100644 index 00000000000..fc85a3c1a4e --- /dev/null +++ b/raster/r.kappa/testsuite/test_r_kappa.py @@ -0,0 +1,296 @@ +""" +Name: r.kappa tests +Purpose: Validates accuracy calculations and output + +Author: Maris Nartiss +Copyright: (C) 2022 by Maris Nartiss and the GRASS Development Team +Licence: This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. +""" + +import os +import pathlib + +from grass.script import read_command +from grass.script.core import tempname +from grass.gunittest.case import TestCase +from grass.gunittest.main import test + + +class MatrixCorrectnessTest(TestCase): + """Test correctness of calculated matrix""" + + @classmethod + def setUpClass(cls): + """Import sample maps with known properties""" + cls.use_temp_region() + cls.runModule("g.region", n=5, s=0, e=5, w=0, res=1) + + cls.data_dir = os.path.join(pathlib.Path(__file__).parent.absolute(), "data") + cls.ref_1 = tempname(10) + cls.runModule( + "r.in.ascii", + input=os.path.join(cls.data_dir, "ref_1.ascii"), + output=cls.ref_1, + quiet=True, + ) + cls.class_1 = tempname(10) + cls.runModule( + "r.in.ascii", + input=os.path.join(cls.data_dir, "class_1.ascii"), + output=cls.class_1, + quiet=True, + ) + + @classmethod + def tearDownClass(cls): + """Remove temporary data""" + cls.del_temp_region() + cls.runModule("g.remove", flags="f", type="raster", name=cls.ref_1) + cls.runModule("g.remove", flags="f", type="raster", name=cls.class_1) + + def test_m(self): + """Test printing matrix only + Implicitly tests calculation of matrix + """ + + ref = """cat#\t1\t2\t3\t4\t5\t6\tRowSum +1\t4\t0\t0\t0\t0\t0\t4 +2\t0\t0\t0\t0\t0\t0\t0 +3\t0\t1\t4\t0\t0\t0\t5 +4\t3\t0\t0\t0\t0\t1\t4 +5\t0\t0\t0\t0\t1\t0\t1 +6\t0\t2\t0\t0\t0\t2\t4 +ColSum\t7\t3\t4\t0\t1\t3\t18 + +""" + out = read_command( + "r.kappa", + reference=self.ref_1, + classification=self.class_1, + flags="m", + quiet=True, + ) + self.assertEqual(out, ref) + + +class CalculationCorrectness1Test(TestCase): + """Test correctness of values in printout mode + First version of reference data""" + + @classmethod + def setUpClass(cls): + """Import sample maps with known properties""" + cls.use_temp_region() + cls.runModule("g.region", n=5, s=0, e=5, w=0, res=1) + + cls.data_dir = os.path.join(pathlib.Path(__file__).parent.absolute(), "data") + cls.ref_1 = tempname(10) + cls.runModule( + "r.in.ascii", + input=os.path.join(cls.data_dir, "ref_1.ascii"), + output=cls.ref_1, + quiet=True, + ) + cls.class_1 = tempname(10) + cls.runModule( + "r.in.ascii", + input=os.path.join(cls.data_dir, "class_1.ascii"), + output=cls.class_1, + quiet=True, + ) + cls.per_class = { + "producer": [ + 100 - 57.143, + 100 - 0.0, + 100 - 100.0, + "NA", + 100 - 100.0, + 100 - 66.666, + ], + "user": [100 - 100.0, "NA", 100 - 80.0, 100 - 0.0, 100 - 100.0, 100 - 50.0], + "cond.kappa": [1.0, "NA", 0.743, 0.0, 1.0, 0.4], + } + + @classmethod + def tearDownClass(cls): + """Remove temporary data""" + cls.del_temp_region() + cls.runModule("g.remove", flags="f", type="raster", name=cls.ref_1) + cls.runModule("g.remove", flags="f", type="raster", name=cls.class_1) + + def match(self, pat, ref): + if pat == "NA" or ref == "NA": + return pat == ref + try: + val = float(pat) + except ValueError: + return False + return ref - val < 0.001 + + # Characteristics of the matrix + # All values were obtained according to formulas given in + # Rossiter 2004. Technical Note: Statistical methods for accuracy + # assessment of classified thematic maps. + # Only exception is Kappa variance as attempts to follow formulas given + # by Rossiter lead to a spectacular failure (most likely due to + # poor math skills of the author of this testing code). Thus Kappa + # variance is not validated as "good" value is not known. + # Overall Cohen Kappa value: 0.52091 + # Observation count: 18 + # Correct count: 11 + # Overall accuracy: 0.61111 + # CAT TP TN FP FN Prod User pii pi+ p+i conditional kappa + # 1 4 11 0 3 0.571 1.000 0.222 0.222 0.389 1.000 + # 2 0 15 0 3 0.000 - 0.000 0.000 0.167 - + # 3 4 13 1 0 1.000 0.800 0.222 0.278 0.222 0.743 + # 4 0 14 4 0 - 0.000 0.000 0.222 0.000 0.000 + # 5 1 17 0 0 1.000 1.000 0.056 0.056 0.056 1.000 + # 6 2 13 2 1 0.667 0.500 0.111 0.222 0.167 0.400 + + def test_standard_output(self): + out = read_command( + "r.kappa", + reference=self.ref_1, + classification=self.class_1, + flags="w", + quiet=True, + ) + rows = out.splitlines() + + # Matrix part + self.assertEqual(rows[10], " M 1\t4\t0\t0\t0\t0\t0\t4") + self.assertEqual(rows[11], " A 2\t0\t0\t0\t0\t0\t0\t0") + self.assertEqual(rows[12], " P 3\t0\t1\t4\t0\t0\t0\t5") + self.assertEqual(rows[13], " 2 4\t3\t0\t0\t0\t0\t1\t4") + self.assertEqual(rows[14], " 5\t0\t0\t0\t0\t1\t0\t1") + self.assertEqual(rows[15], " 6\t0\t2\t0\t0\t0\t2\t4") + self.assertEqual(rows[16], "Col Sum\t\t7\t3\t4\t0\t1\t3\t18") + + # Per class coefficients + for c in range(len(self.per_class["producer"])): + vals = rows[20 + c].split() + # The test on the next line is valid only for this data + self.assertEqual(vals[0], str(c + 1)) + self.assertTrue(self.match(vals[1], self.per_class["user"][c])) + self.assertTrue(self.match(vals[2], self.per_class["producer"][c])) + self.assertTrue(self.match(vals[3], self.per_class["cond.kappa"][c])) + + # Kappa value + vals = rows[28].split() + self.assertTrue(self.match(vals[0], 0.52091)) + + # Overall characteristics + vals = rows[31].split() + self.assertEqual(vals[0], "11") + self.assertEqual(vals[1], "18") + self.assertTrue(self.match(vals[2], 61.111)) + + +class CalculationCorrectness2Test(TestCase): + """Test correctness of values in printout mode + A pathological case when no values match""" + + @classmethod + def setUpClass(cls): + """Import sample maps with known properties""" + cls.use_temp_region() + cls.runModule("g.region", n=5, s=0, e=5, w=0, res=1) + + cls.data_dir = os.path.join(pathlib.Path(__file__).parent.absolute(), "data") + cls.ref_1 = tempname(10) + cls.runModule( + "r.in.ascii", + input=os.path.join(cls.data_dir, "ref_2.ascii"), + output=cls.ref_1, + quiet=True, + ) + cls.class_1 = tempname(10) + cls.runModule( + "r.in.ascii", + input=os.path.join(cls.data_dir, "class_2.ascii"), + output=cls.class_1, + quiet=True, + ) + cls.per_class = { + "producer": [ + 100.0, + 100.0, + 100.0, + 100.0, + 100.0, + "NA", + ], + "user": ["NA", "NA", "NA", "NA", "NA", 100.0], + "cond.kappa": ["NA", "NA", "NA", "NA", "NA", 0.0], + } + + @classmethod + def tearDownClass(cls): + """Remove temporary data""" + cls.del_temp_region() + # cls.runModule("g.remove", flags="f", type="raster", name=cls.ref_1) + # cls.runModule("g.remove", flags="f", type="raster", name=cls.class_1) + + def match(self, pat, ref): + if pat == "NA" or ref == "NA": + return pat == ref + try: + val = float(pat) + except ValueError: + return False + return ref - val < 0.001 + + # Characteristics of the matrix + # Overall Cohen Kappa value: 0.0 + # Observation count: 25 + # Correct count: 0 + # Overall accuracy: 0.0 + # CAT TP TN FP FN User Producer + # 0 0 17 0 8 - 0 + # 1 0 17 0 8 - 0 + # 2 0 21 0 4 - 0 + # 3 0 24 0 1 - 0 + # 4 0 21 0 4 - 0 + # 9 0 0 25 0 0 - + + def test_standard_output(self): + out = read_command( + "r.kappa", + reference=self.ref_1, + classification=self.class_1, + flags="w", + quiet=True, + ) + rows = out.splitlines() + + # Matrix part + self.assertEqual(rows[10], " M 0\t0\t0\t0\t0\t0\t0\t0") + self.assertEqual(rows[11], " A 1\t0\t0\t0\t0\t0\t0\t0") + self.assertEqual(rows[12], " P 2\t0\t0\t0\t0\t0\t0\t0") + self.assertEqual(rows[13], " 2 3\t0\t0\t0\t0\t0\t0\t0") + self.assertEqual(rows[14], " 4\t0\t0\t0\t0\t0\t0\t0") + self.assertEqual(rows[15], " 9\t4\t8\t8\t4\t1\t0\t25") + self.assertEqual(rows[16], "Col Sum\t\t4\t8\t8\t4\t1\t0\t25") + + # Per class coefficients + for c in range(len(self.per_class["producer"])): + vals = rows[20 + c].split() + self.assertTrue(self.match(vals[1], self.per_class["user"][c])) + self.assertTrue(self.match(vals[2], self.per_class["producer"][c])) + self.assertTrue(self.match(vals[3], self.per_class["cond.kappa"][c])) + + # Kappa value + vals = rows[28].split() + self.assertTrue(self.match(vals[0], 0.0)) + + # Overall characteristics + vals = rows[31].split() + self.assertEqual(vals[0], "0") + self.assertEqual(vals[1], "25") + self.assertTrue(self.match(vals[2], 0.0)) + + +if __name__ == "__main__": + test() From cdf42e8bed1dfb536e331e937c4c753c9ce885ab Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Sun, 6 Nov 2022 21:48:03 +0100 Subject: [PATCH 062/123] Fix -Wunused-result compiler warnings (#2166) * -Wunused-result compiler warnings addressed in following parts: GRASS Modules: d.mon g.proj g.rename ps.map r.fill.dir r.grow.distance r.in.ascii r.in.bin r.in.gridatb r.in.mat r.param.scale r.topmodel v.vol.rst GRASS Library parts: lib/bitmap lib/cairodriver lib/db/dbmi_driver lib/gis lib/rst/interp_float lib/vector/Vlib/ Almost exclusively these fixes are file I/O related, handling return values from calls with read()/fread(), write()/fwrite(), fgets(), fscanf(), getcwd(). In addition, potential overflow of int before it is converted to size_t was avoided in r.in.mat/main.c --- display/d.mon/start.c | 34 ++++++++++------ general/g.proj/input.c | 3 +- general/g.rename/main.c | 19 ++++++--- lib/bitmap/bitmap.c | 59 +++++++++++++++++++++------- lib/cairodriver/read_bmp.c | 10 ++++- lib/db/dbmi_driver/d_error.c | 7 +++- lib/gis/error.c | 3 +- lib/gis/writ_zeros.c | 21 +++++----- lib/rst/interp_float/output2d.c | 38 ++++++++++++------ lib/rst/interp_float/resout2d.c | 36 +++++++++++------ lib/vector/Vlib/break_polygons.c | 25 +++++++++--- ps/ps.map/eps.c | 6 ++- raster/r.fill.dir/dopolys.c | 10 ++++- raster/r.fill.dir/filldir.c | 10 ++++- raster/r.fill.dir/main.c | 17 ++++++-- raster/r.fill.dir/ppupdate.c | 14 +++++-- raster/r.fill.dir/resolve.c | 18 ++++++--- raster/r.fill.dir/wtrshed.c | 42 +++++++++++++++----- raster/r.grow.distance/main.c | 33 ++++++++++++---- raster/r.in.ascii/gethead.c | 5 ++- raster/r.in.ascii/main.c | 4 +- raster/r.in.bin/main.c | 18 ++++++--- raster/r.in.gridatb/file_io.c | 10 +++-- raster/r.in.mat/main.c | 63 ++++++++++++++++++++---------- raster/r.param.scale/disp_matrix.c | 5 ++- raster/r.topmodel/file_io.c | 3 +- vector/v.vol.rst/user1.c | 8 +++- 27 files changed, 375 insertions(+), 146 deletions(-) diff --git a/display/d.mon/start.c b/display/d.mon/start.c index d4d7407500a..5542ab6f623 100644 --- a/display/d.mon/start.c +++ b/display/d.mon/start.c @@ -185,27 +185,35 @@ int start_mon(const char *name, const char *output, int select, if (G_strncasecmp(name, "wx", 2) == 0) { sprintf(buf, "GRASS_RENDER_IMMEDIATE=default\n"); /* TODO: read settings from wxGUI */ - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); sprintf(buf, "GRASS_RENDER_FILE_READ=FALSE\n"); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); sprintf(buf, "GRASS_RENDER_TRANSPARENT=TRUE\n"); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); } else { sprintf(buf, "GRASS_RENDER_IMMEDIATE=%s\n", name); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); sprintf(buf, "GRASS_RENDER_FILE_READ=TRUE\n"); - write(fd, buf, strlen(buf)); - + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); } sprintf(buf, "GRASS_RENDER_FILE=%s\n", out_file); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); sprintf(buf, "GRASS_RENDER_WIDTH=%d\n", width); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); sprintf(buf, "GRASS_RENDER_HEIGHT=%d\n", height); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); sprintf(buf, "GRASS_LEGEND_FILE=%s\n", leg_file); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); if (bgcolor) { @@ -213,11 +221,13 @@ int start_mon(const char *name, const char *output, int select, sprintf(buf, "GRASS_RENDER_TRANSPARENT=TRUE\n"); else sprintf(buf, "GRASS_RENDER_BACKGROUNDCOLOR=%s\n", bgcolor); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); } if (truecolor) { sprintf(buf, "GRASS_RENDER_TRUECOLOR=TRUE\n"); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + G_fatal_error(_("Failed to write to file <%s>"), env_file); } close(fd); diff --git a/general/g.proj/input.c b/general/g.proj/input.c index 8a6b010415b..eab97afa2da 100644 --- a/general/g.proj/input.c +++ b/general/g.proj/input.c @@ -229,7 +229,8 @@ int input_proj4(char *proj4params) * OSRImportFromWkt */ if (strcmp(proj4params, "-") == 0) { infd = stdin; - fgets(buff, sizeof(buff), infd); + if (fgets(buff, sizeof(buff), infd) == NULL) + G_warning(_("Failed to read PROJ.4 parameter from stdin")); } else strcpy(buff, proj4params); diff --git a/general/g.rename/main.c b/general/g.rename/main.c index 5161d9d7bf4..3c8edb287f6 100644 --- a/general/g.rename/main.c +++ b/general/g.rename/main.c @@ -119,7 +119,7 @@ void update_reclass_maps(const char *name, const char *mapset) for (; *rmaps; rmaps++) { char buf1[256], buf2[256], buf3[256], *str; FILE *fp; - int ptr, l; + off_t ptr, l; G_message(" %s", *rmaps); sprintf(buf3, "%s", *rmaps); @@ -136,9 +136,12 @@ void update_reclass_maps(const char *name, const char *mapset) if (fp == NULL) continue; - fgets(buf2, 255, fp); - fgets(buf2, 255, fp); - fgets(buf2, 255, fp); + if (fgets(buf2, 255, fp) == NULL) + continue; + if (fgets(buf2, 255, fp) == NULL) + continue; + if (fgets(buf2, 255, fp) == NULL) + continue; ptr = G_ftell(fp); G_fseek(fp, 0L, SEEK_END); @@ -146,14 +149,18 @@ void update_reclass_maps(const char *name, const char *mapset) str = (char *)G_malloc(l); G_fseek(fp, ptr, SEEK_SET); - fread(str, l, 1, fp); + if (fread(str, l, 1, fp) != 1) { + if (ferror(fp)) + G_fatal_error(_("Failed to read reclass maps file")); + } fclose(fp); fp = fopen(buf1, "w"); fprintf(fp, "reclass\n"); fprintf(fp, "name: %s\n", name); fprintf(fp, "mapset: %s\n", mapset); - fwrite(str, l, 1, fp); + if (fwrite(str, l, 1, fp) < 1 & l > 0) + G_fatal_error(_("Failed to write full reclass maps file")); G_free(str); fclose(fp); } diff --git a/lib/bitmap/bitmap.c b/lib/bitmap/bitmap.c index ed528d7779d..431fe7ade8a 100644 --- a/lib/bitmap/bitmap.c +++ b/lib/bitmap/bitmap.c @@ -69,13 +69,11 @@ struct BM *BM_create(int x, int y) map->bytes = (x + 7) / 8; - void *tmp_map_data = - (unsigned char *)calloc(map->bytes * y, sizeof(char)); - if (tmp_map_data == NULL) { + if (NULL == + (map->data = (unsigned char *)calloc(map->bytes * y, sizeof(char)))) { free(map); return (NULL); } - map->data = tmp_map_data; map->rows = y; map->cols = x; @@ -326,21 +324,36 @@ struct BM *BM_file_read(FILE * fp) if (NULL == (map = (struct BM *)malloc(sizeof(struct BM)))) return (NULL); - fread(&c, sizeof(char), sizeof(char), fp); + if (fread(&c, sizeof(char), sizeof(char), fp) != sizeof(char)) + return NULL; if (c != BM_MAGIC) { free(map); return NULL; } - fread(buf, BM_TEXT_LEN, sizeof(char), fp); + if (fread(buf, BM_TEXT_LEN, sizeof(char), fp) != sizeof(char)) { + free(map); + return NULL; + } - fread(&c, sizeof(char), sizeof(char), fp); + if (fread(&c, sizeof(char), sizeof(char), fp) != sizeof(char)) { + free(map); + return NULL; + } map->sparse = c; - fread(&(map->rows), sizeof(map->rows), sizeof(char), fp); + if (fread(&(map->rows), sizeof(map->rows), sizeof(char), fp) != + sizeof(char)) { + free(map); + return NULL; + } - fread(&(map->cols), sizeof(map->cols), sizeof(char), fp); + if (fread(&(map->cols), sizeof(map->cols), sizeof(char), fp) != + sizeof(char)) { + free(map); + return NULL; + } map->bytes = (map->cols + 7) / 8; @@ -355,8 +368,12 @@ struct BM *BM_file_read(FILE * fp) for (i = 0; i < map->rows; i++) if (map->bytes != - fread(&(map->data[i * map->bytes]), sizeof(char), map->bytes, fp)) + fread(&(map->data[i * map->bytes]), sizeof(char), map->bytes, + fp)) { + free(map->data); + free(map); return NULL; + } return map; @@ -368,12 +385,18 @@ struct BM *BM_file_read(FILE * fp) if (NULL == (map->data = (unsigned char *) - malloc(sizeof(struct BMlink *) * map->rows))) + malloc(sizeof(struct BMlink *) * map->rows))) { + free(map); return (NULL); + } for (y = 0; y < map->rows; y++) { /* first get number of links */ - fread(&i, sizeof(i), sizeof(char), fp); + if (fread(&i, sizeof(i), sizeof(char), fp) != sizeof(char)) { + free(map->data); + free(map); + return NULL; + } cnt = i; @@ -390,10 +413,18 @@ struct BM *BM_file_read(FILE * fp) p = p2; } - fread(&n, sizeof(n), sizeof(char), fp); + if (fread(&n, sizeof(n), sizeof(char), fp) != sizeof(char)) { + free(map->data); + free(map); + return NULL; + } p->count = n; - fread(&n, sizeof(n), sizeof(char), fp); + if (fread(&n, sizeof(n), sizeof(char), fp) != sizeof(char)) { + free(map->data); + free(map); + return NULL; + } p->val = n; p->next = NULL; } diff --git a/lib/cairodriver/read_bmp.c b/lib/cairodriver/read_bmp.c index 68b4cb3e5ce..7a7508531fc 100644 --- a/lib/cairodriver/read_bmp.c +++ b/lib/cairodriver/read_bmp.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -94,7 +95,14 @@ void cairo_read_bmp(void) if (!read_bmp_header(header)) G_fatal_error(_("Cairo: Invalid BMP header for <%s>"), ca.file_name); - fread(ca.grid, ca.stride, ca.height, input); + if (fread(ca.grid, ca.stride, ca.height, input) != ca.height) { + if (feof(input)) + G_fatal_error(_("Cairo: error reading BMP file <%s>: " + "unexpected end of file"), ca.file_name); + else if (ferror(input)) + G_fatal_error(_("Cairo: error reading BMP file <%s>: %s"), + ca.file_name, strerror(errno)); + } fclose(input); } diff --git a/lib/db/dbmi_driver/d_error.c b/lib/db/dbmi_driver/d_error.c index 226cef2f137..15cca2253df 100644 --- a/lib/db/dbmi_driver/d_error.c +++ b/lib/db/dbmi_driver/d_error.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -76,7 +77,11 @@ void db_d_append_error(const char *fmt, ...) count = vfprintf(fp, fmt, ap); if (count >= 0 && (work = G_calloc(count + 1, 1))) { rewind(fp); - fread(work, 1, count, fp); + if (fread(work, 1, count, fp) != count) { + if (ferror(fp)) + G_fatal_error(_("DBMI-%s driver file reading error: %s"), + st->driver_name, strerror(errno)); + } db_append_string(st->errMsg, work); G_free(work); } diff --git a/lib/gis/error.c b/lib/gis/error.c index 25994d4397b..482dced80d0 100644 --- a/lib/gis/error.c +++ b/lib/gis/error.c @@ -341,7 +341,8 @@ static void log_error(const char *msg, int fatal) clock = time(NULL); /* get current working directory */ - getcwd(cwd, sizeof(cwd)); + if (getcwd(cwd, sizeof(cwd)) == NULL) + sprintf(cwd, "%s", _("unknown")); /* write the error log file */ if ((gisbase = G_gisbase())) diff --git a/lib/gis/writ_zeros.c b/lib/gis/writ_zeros.c index 440a5d57b67..2bc5b251a95 100644 --- a/lib/gis/writ_zeros.c +++ b/lib/gis/writ_zeros.c @@ -14,12 +14,15 @@ * \date 1999-2014 */ +#include #include +#include #include +#include /** - * \brief Writes n bytes of 9 to file descriptor fd + * \brief Writes n bytes of zero to file descriptor fd * * \param[in] fd file descriptor * \param[in] n number of bytes to write @@ -30,22 +33,16 @@ void G_write_zeros(int fd, size_t n) { char zeros[1024]; char *z; - int i; + size_t i; if (n <= 0) return; - /* There is a subtle gotcha to be avoided here. - * - * i must be an int for the write, but n (size_t) can be long or larger. - * Must be careful not to cast long to int, hence - * avoid i = n unless n is within range of int */ - /* fill zeros buffer with zeros */ if (n > sizeof(zeros)) i = sizeof(zeros); else - i = n; /* this is ok here */ + i = n; z = zeros; while (i--) @@ -56,9 +53,11 @@ void G_write_zeros(int fd, size_t n) if (n > sizeof(zeros)) i = sizeof(zeros); else - i = n; /* this is ok here */ + i = n; - write(fd, zeros, i); + if (write(fd, zeros, i) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), + __func__, errno, strerror(errno)); n -= i; } } diff --git a/lib/rst/interp_float/output2d.c b/lib/rst/interp_float/output2d.c index 572c6627a9a..93e5665b405 100644 --- a/lib/rst/interp_float/output2d.c +++ b/lib/rst/interp_float/output2d.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -66,7 +67,7 @@ int IL_output_2d(struct interp_params *params, struct Cell_head *cellhd, FCELL *cell1; int cf1 = -1, cf2 = -1, cf3 = -1, cf4 = -1, cf5 = -1, cf6 = -1; int nrows, ncols; - int i, ii; + int i; double zstep; FCELL data1, data2; struct Colors colors; @@ -126,13 +127,11 @@ int IL_output_2d(struct interp_params *params, struct Cell_head *cellhd, /* seek to the right row */ G_fseek(params->Tmp_fd_z, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - ii = fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_z); - /* - * for(j=0;jnsizc;j++) fprintf(stderr,"%f ",cell1[j]); - * fprintf(stderr,"\n"); - */ + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_z) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf1, cell1); - } } @@ -142,7 +141,10 @@ int IL_output_2d(struct interp_params *params, struct Cell_head *cellhd, /* seek to the right row */ G_fseek(params->Tmp_fd_dx, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_dx); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_dx) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf2, cell1); } } @@ -153,7 +155,10 @@ int IL_output_2d(struct interp_params *params, struct Cell_head *cellhd, /* seek to the right row */ G_fseek(params->Tmp_fd_dy, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_dy); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_dy) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf3, cell1); } } @@ -164,7 +169,10 @@ int IL_output_2d(struct interp_params *params, struct Cell_head *cellhd, /* seek to the right row */ G_fseek(params->Tmp_fd_xx, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_xx); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_xx) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf4, cell1); } } @@ -175,7 +183,10 @@ int IL_output_2d(struct interp_params *params, struct Cell_head *cellhd, /* seek to the right row */ G_fseek(params->Tmp_fd_yy, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_yy); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_yy) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf5, cell1); } } @@ -186,7 +197,10 @@ int IL_output_2d(struct interp_params *params, struct Cell_head *cellhd, /* seek to the right row */ G_fseek(params->Tmp_fd_xy, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_xy); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_xy) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf6, cell1); } } diff --git a/lib/rst/interp_float/resout2d.c b/lib/rst/interp_float/resout2d.c index f7d1264fb3f..3805c17cce2 100644 --- a/lib/rst/interp_float/resout2d.c +++ b/lib/rst/interp_float/resout2d.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -117,7 +118,10 @@ int IL_resample_output_2d(struct interp_params *params, double zmin, double zmax /* seek to the right row */ G_fseek(params->Tmp_fd_z, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_z); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_z) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf1, cell1); } } @@ -128,12 +132,10 @@ int IL_resample_output_2d(struct interp_params *params, double zmin, double zmax /* seek to the right row */ G_fseek(params->Tmp_fd_dx, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_dx); - /* - * for (ii==0;iinsizc;ii++) { fprintf(stderr,"ii=%d ",ii); - * fprintf(stderr,"%f ",cell1[ii]); } - * fprintf(stderr,"params->nsizc=%d \n",params->nsizc); - */ + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_dx) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf2, cell1); } } @@ -144,7 +146,10 @@ int IL_resample_output_2d(struct interp_params *params, double zmin, double zmax /* seek to the right row */ G_fseek(params->Tmp_fd_dy, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_dy); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_dy) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf3, cell1); } } @@ -155,7 +160,10 @@ int IL_resample_output_2d(struct interp_params *params, double zmin, double zmax /* seek to the right row */ G_fseek(params->Tmp_fd_xx, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_xx); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_xx) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf4, cell1); } } @@ -166,7 +174,10 @@ int IL_resample_output_2d(struct interp_params *params, double zmin, double zmax /* seek to the right row */ G_fseek(params->Tmp_fd_yy, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_yy); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_yy) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf5, cell1); } } @@ -177,7 +188,10 @@ int IL_resample_output_2d(struct interp_params *params, double zmin, double zmax /* seek to the right row */ G_fseek(params->Tmp_fd_xy, (off_t) (params->nsizr - 1 - i) * params->nsizc * sizeof(FCELL), 0); - fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_xy); + if (fread(cell1, sizeof(FCELL), params->nsizc, params->Tmp_fd_xy) + != params->nsizc) + G_fatal_error(_("RST library temporary file reading error: %s"), + strerror(errno)); Rast_put_f_row(cf6, cell1); } } diff --git a/lib/vector/Vlib/break_polygons.c b/lib/vector/Vlib/break_polygons.c index 1b1293efceb..9f9f9f639e2 100644 --- a/lib/vector/Vlib/break_polygons.c +++ b/lib/vector/Vlib/break_polygons.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -227,7 +228,9 @@ void Vect_break_polygons_file(struct Map_info *Map, int type, if (fpoint > 0) { /* Found */ /* read point */ lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET); - read(xpntfd, &XPnt, sizeof(XPNT2)); + if (read(xpntfd, &XPnt, sizeof(XPNT2)) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), + __func__, errno, strerror(errno)); if (XPnt.cross == 1) continue; /* already marked */ @@ -238,7 +241,9 @@ void Vect_break_polygons_file(struct Map_info *Map, int type, /* write point */ lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET); - write(xpntfd, &XPnt, sizeof(XPNT2)); + if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), + __func__, errno, strerror(errno)); } else { G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1, @@ -252,7 +257,9 @@ void Vect_break_polygons_file(struct Map_info *Map, int type, /* write point */ lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET); - write(xpntfd, &XPnt, sizeof(XPNT2)); + if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), + __func__, errno, strerror(errno)); } } } @@ -274,7 +281,9 @@ void Vect_break_polygons_file(struct Map_info *Map, int type, /* write point */ lseek(xpntfd, (off_t) (npoints - 1) * sizeof(XPNT2), SEEK_SET); - write(xpntfd, &XPnt, sizeof(XPNT2)); + if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), + __func__, errno, strerror(errno)); npoints++; } @@ -332,7 +341,9 @@ void Vect_break_polygons_file(struct Map_info *Map, int type, /* read point */ lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET); - read(xpntfd, &XPnt, sizeof(XPNT2)); + if (read(xpntfd, &XPnt, sizeof(XPNT2)) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); /* break or write last segment of broken line */ if ((j == (Points->n_points - 1) && broken) || XPnt.cross) { @@ -367,7 +378,9 @@ void Vect_break_polygons_file(struct Map_info *Map, int type, /* write point */ lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET); - write(xpntfd, &XPnt, sizeof(XPNT2)); + if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), + __func__, errno, strerror(errno)); } } diff --git a/ps/ps.map/eps.c b/ps/ps.map/eps.c index ff4bb0375da..473da3992b5 100644 --- a/ps/ps.map/eps.c +++ b/ps/ps.map/eps.c @@ -19,7 +19,11 @@ int eps_bbox(char *eps, double *llx, double *lly, double *urx, double *ury) return (0); } /* test if first row contains '%!PS-Adobe-m.n EPSF-m.n' string */ - fgets(buf, 200, fp); + if (fgets(buf, 200, fp) == NULL) { + G_warning(_("Failed to read eps file <%s>"), eps); + fclose(fp); + return (0); + } if (sscanf(buf, "%%!PS-Adobe-%d.%d EPSF-%d.%d", &v1, &v2, &v3, &v4) < 4) { fprintf(stderr, "file <%s> is not in EPS format\n", eps); fclose(fp); diff --git a/raster/r.fill.dir/dopolys.c b/raster/r.fill.dir/dopolys.c index b1037aab04e..aaeac0cccd9 100644 --- a/raster/r.fill.dir/dopolys.c +++ b/raster/r.fill.dir/dopolys.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include @@ -53,7 +55,9 @@ int dopolys(int fd, int fm, int nl, int ns) lseek(fd, bufsz, SEEK_SET); for (i = 1; i < nl - 1; i += 1) { - read(fd, dir, bufsz); + if (read(fd, dir, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); for (j = 1; j < ns - 1; j += 1) { if (Rast_is_c_null_value(&dir[j]) || dir[j] >= 0) continue; @@ -94,7 +98,9 @@ int dopolys(int fd, int fm, int nl, int ns) dir[cells[cnt + 1]] = cells[cnt + 2]; cnt += 3; } - write(fm, dir, bufsz); + if (write(fm, dir, bufsz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); } G_free(cells); diff --git a/raster/r.fill.dir/filldir.c b/raster/r.fill.dir/filldir.c index f898431d6eb..a6580aa0803 100644 --- a/raster/r.fill.dir/filldir.c +++ b/raster/r.fill.dir/filldir.c @@ -4,8 +4,10 @@ #include #include #include +#include #include #include +#include #include "tinf.h" /* get the slope between two cells and return a slope direction */ @@ -153,7 +155,9 @@ void filldir(int fe, int fd, int nl, struct band3 *bnd) advance_band3(fe, bnd); if (fill_row(nl, bnd->ns, bnd)) { lseek(fe, (off_t) i * bnd->sz, SEEK_SET); - write(fe, bnd->b[1], bnd->sz); + if (write(fe, bnd->b[1], bnd->sz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); } } /* why on the last row? it's an outer row */ @@ -176,7 +180,9 @@ void filldir(int fe, int fd, int nl, struct band3 *bnd) for (i = 0; i < nl; i += 1) { advance_band3(fe, bnd); build_one_row(i, nl, bnd->ns, bnd, dir); - write(fd, dir, bufsz); + if (write(fd, dir, bufsz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); } /* why this extra row ? */ #if 0 diff --git a/raster/r.fill.dir/main.c b/raster/r.fill.dir/main.c index 4905bc108d2..83074962c6e 100644 --- a/raster/r.fill.dir/main.c +++ b/raster/r.fill.dir/main.c @@ -38,6 +38,7 @@ #include #include #include +#include /* for using the "open" statement */ #include @@ -195,7 +196,9 @@ int main(int argc, char **argv) for (i = 0; i < nrows; i++) { G_percent(i, nrows, 2); get_row(map_id, in_buf, i); - write(fe, in_buf, bnd.sz); + if (write(fe, in_buf, bnd.sz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); } G_percent(1, 1, 1); Rast_close(map_id); @@ -246,7 +249,9 @@ int main(int argc, char **argv) bas_id = Rast_open_new(bas_name, CELL_TYPE); for (i = 0; i < nrows; i++) { - read(fm, out_buf, bufsz); + if (read(fm, out_buf, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); Rast_put_row(bas_id, out_buf, CELL_TYPE); } @@ -261,10 +266,14 @@ int main(int argc, char **argv) G_important_message(_("Writing output raster maps...")); for (i = 0; i < nrows; i++) { G_percent(i, nrows, 5); - read(fe, in_buf, bnd.sz); + if (read(fe, in_buf, bnd.sz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); put_row(new_id, in_buf); - read(fd, out_buf, bufsz); + if (read(fd, out_buf, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); for (j = 0; j < ncols; j += 1) out_buf[j] = dir_type(type, out_buf[j]); diff --git a/raster/r.fill.dir/ppupdate.c b/raster/r.fill.dir/ppupdate.c index 84be28e92e7..202dba695bb 100644 --- a/raster/r.fill.dir/ppupdate.c +++ b/raster/r.fill.dir/ppupdate.c @@ -1,7 +1,9 @@ #include #include +#include #include #include +#include #include "tinf.h" struct links @@ -203,8 +205,12 @@ void ppupdate(int fe, int fb, int nl, int nbasins, struct band3 *elev, lseek(fe, 0, SEEK_SET); lseek(fb, 0, SEEK_SET); for (i = 0; i < nl; i += 1) { - read(fe, elev->b[1], elev->sz); - read(fb, basins->b[1], basins->sz); + if (read(fe, elev->b[1], elev->sz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); + if (read(fb, basins->b[1], basins->sz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); for (j = 0; j < basins->ns; j += 1) { ii = *((CELL *) basins->b[1] + j); if (ii <= 0) @@ -213,7 +219,9 @@ void ppupdate(int fe, int fb, int nl, int nbasins, struct band3 *elev, memcpy(this_elev, get_max(this_elev, list[ii].pp), bpe()); } lseek(fe, -elev->sz, SEEK_CUR); - write(fe, elev->b[1], elev->sz); + if (write(fe, elev->b[1], elev->sz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); } G_free(list); diff --git a/raster/r.fill.dir/resolve.c b/raster/r.fill.dir/resolve.c index 99bc6c5572c..8a4bfe70cea 100644 --- a/raster/r.fill.dir/resolve.c +++ b/raster/r.fill.dir/resolve.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -109,7 +110,9 @@ void resolve(int fd, int nl, struct band3 *bnd) /* select a direction when there are multiple non-flat links */ lseek(fd, bnd->sz, SEEK_SET); for (i = 1; i < nl - 1; i += 1) { - read(fd, bnd->b[0], bnd->sz); + if (read(fd, bnd->b[0], bnd->sz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); for (j = 1; j < bnd->ns - 1; j += 1) { offset = j * isz; if (Rast_is_c_null_value((CELL *) (bnd->b[0] + offset))) @@ -120,7 +123,9 @@ void resolve(int fd, int nl, struct band3 *bnd) memcpy(bnd->b[0] + offset, &cvalue, isz); } lseek(fd, -bnd->sz, SEEK_CUR); - write(fd, bnd->b[0], bnd->sz); + if (write(fd, bnd->b[0], bnd->sz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); } pass = 0; @@ -159,8 +164,9 @@ void resolve(int fd, int nl, struct band3 *bnd) } while (goagain); lseek(fd, (off_t) i * bnd->sz, SEEK_SET); - write(fd, bnd->b[1], bnd->sz); - + if (write(fd, bnd->b[1], bnd->sz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); } if (!activity) { @@ -196,7 +202,9 @@ void resolve(int fd, int nl, struct band3 *bnd) } while (goagain); lseek(fd, (off_t) i * bnd->sz, SEEK_SET); - write(fd, bnd->b[1], bnd->sz); + if (write(fd, bnd->b[1], bnd->sz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); } if (!activity) { diff --git a/raster/r.fill.dir/wtrshed.c b/raster/r.fill.dir/wtrshed.c index 28dbef83a31..03f29d1b751 100644 --- a/raster/r.fill.dir/wtrshed.c +++ b/raster/r.fill.dir/wtrshed.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -105,10 +107,14 @@ void wtrshed(int fm, int fd, int nl, int ns, int mxbuf) bas[i].offset = dir[i].offset = (off_t) rdline *bufsz; lseek(fm, bas[i].offset, SEEK_SET); - read(fm, bas[i].p, bufsz); + if (read(fm, bas[i].p, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); lseek(fd, dir[i].offset, SEEK_SET); - read(fd, dir[i].p, bufsz); + if (read(fd, dir[i].p, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); rdline++; } @@ -125,7 +131,9 @@ void wtrshed(int fm, int fd, int nl, int ns, int mxbuf) /* write one line */ lseek(fm, bas[sline].offset, SEEK_SET); - write(fm, bas[sline].p, bufsz); + if (write(fm, bas[sline].p, bufsz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); /* If the bottom end of the buffers reach the bottom of the file, * rotate the buffers and read new lines */ @@ -144,10 +152,14 @@ void wtrshed(int fm, int fd, int nl, int ns, int mxbuf) (off_t) rdline *bufsz; lseek(fm, bas[mxbuf - 1].offset, SEEK_SET); - read(fm, bas[mxbuf - 1].p, bufsz); + if (read(fm, bas[mxbuf - 1].p, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), + __func__, errno, strerror(errno)); lseek(fd, dir[mxbuf - 1].offset, SEEK_SET); - read(fd, dir[mxbuf - 1].p, bufsz); + if (read(fd, dir[mxbuf - 1].p, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), + __func__, errno, strerror(errno)); rdline++; } @@ -167,10 +179,14 @@ void wtrshed(int fm, int fd, int nl, int ns, int mxbuf) bas[i].offset = dir[i].offset = (off_t) rdline *bufsz; lseek(fm, bas[i].offset, SEEK_SET); - read(fm, bas[i].p, bufsz); + if (read(fm, bas[i].p, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); lseek(fd, dir[i].offset, SEEK_SET); - read(fd, dir[i].p, bufsz); + if (read(fd, dir[i].p, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); rdline--; } @@ -188,7 +204,9 @@ void wtrshed(int fm, int fd, int nl, int ns, int mxbuf) /* write one line */ lseek(fm, bas[nline - 1].offset, SEEK_SET); - write(fm, bas[nline - 1].p, bufsz); + if (write(fm, bas[nline - 1].p, bufsz) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); /* Until the top of the buffers reach the top of the file, * rotate the buffers and read new lines */ @@ -206,10 +224,14 @@ void wtrshed(int fm, int fd, int nl, int ns, int mxbuf) bas[0].offset = dir[0].offset = (off_t) rdline *bufsz; lseek(fm, bas[0].offset, SEEK_SET); - read(fm, bas[0].p, bufsz); + if (read(fm, bas[0].p, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), + __func__, errno, strerror(errno)); lseek(fd, dir[0].offset, SEEK_SET); - read(fd, dir[0].p, bufsz); + if (read(fd, dir[0].p, bufsz) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), + __func__, errno, strerror(errno)); rdline--; } diff --git a/raster/r.grow.distance/main.c b/raster/r.grow.distance/main.c index 01753677bc2..4b3c3547c65 100644 --- a/raster/r.grow.distance/main.c +++ b/raster/r.grow.distance/main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -355,10 +356,18 @@ int main(int argc, char **argv) check(irow, col, 1, 1); } - write(temp_fd, new_x_row, ncols * sizeof(CELL)); - write(temp_fd, new_y_row, ncols * sizeof(CELL)); - write(temp_fd, dist_row, ncols * sizeof(DCELL)); - write(temp_fd, new_val_row, ncols * sizeof(DCELL)); + if (write(temp_fd, new_x_row, ncols * sizeof(CELL)) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); + if (write(temp_fd, new_y_row, ncols * sizeof(CELL)) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); + if (write(temp_fd, dist_row, ncols * sizeof(DCELL)) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); + if (write(temp_fd, new_val_row, ncols * sizeof(DCELL)) < 0) + G_fatal_error(_("File writing error in %s() %d:%s"), __func__, + errno, strerror(errno)); swap_rows(); } @@ -380,10 +389,18 @@ int main(int argc, char **argv) lseek(temp_fd, offset, SEEK_SET); - read(temp_fd, new_x_row, ncols * sizeof(CELL)); - read(temp_fd, new_y_row, ncols * sizeof(CELL)); - read(temp_fd, dist_row, ncols * sizeof(DCELL)); - read(temp_fd, new_val_row, ncols * sizeof(DCELL)); + if (read(temp_fd, new_x_row, ncols * sizeof(CELL)) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); + if (read(temp_fd, new_y_row, ncols * sizeof(CELL)) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); + if (read(temp_fd, dist_row, ncols * sizeof(DCELL)) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); + if (read(temp_fd, new_val_row, ncols * sizeof(DCELL)) < 0) + G_fatal_error(_("File reading error in %s() %d:%s"), __func__, + errno, strerror(errno)); for (col = 0; col < ncols; col++) { check(row, col, -1, -1); diff --git a/raster/r.in.ascii/gethead.c b/raster/r.in.ascii/gethead.c index c143387629b..19dd3911957 100644 --- a/raster/r.in.ascii/gethead.c +++ b/raster/r.in.ascii/gethead.c @@ -30,7 +30,10 @@ int getgrdhead(FILE * fd, struct Cell_head *cellhd) rewind(fd); /* read and check the flag on the first line */ - fgets(grd_flag, sizeof(grd_flag), fd); + if (fgets(grd_flag, sizeof(grd_flag), fd) == NULL) { + G_warning(_("failed to read the input file")); + return 0; + } if (strncmp(gs_ascii_flag, grd_flag, strlen(gs_ascii_flag))) { G_warning(_("input file is not a Surfer ascii grid file")); return 0; diff --git a/raster/r.in.ascii/main.c b/raster/r.in.ascii/main.c index 651e5d560e4..ca47bb804f0 100644 --- a/raster/r.in.ascii/main.c +++ b/raster/r.in.ascii/main.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -233,7 +234,8 @@ int main(int argc, char *argv[]) } for (row = 0; row < nrows; row += 1) { - fread(rast, Rast_cell_size(data_type), ncols, ft); + if (fread(rast, Rast_cell_size(data_type), ncols, ft) != ncols) + G_fatal_error(_("Read from file error: %s"), strerror(errno)); Rast_put_row(cf, rast, data_type); G_fseek(ft, sz, SEEK_CUR); } diff --git a/raster/r.in.bin/main.c b/raster/r.in.bin/main.c index 25d37d6a70a..2a2d6e5ee44 100644 --- a/raster/r.in.bin/main.c +++ b/raster/r.in.bin/main.c @@ -109,12 +109,18 @@ static void read_gmt_header(struct GRD_HEADER *header, int swap_flag, read_double(fp, swap_flag, &header->z_scale_factor); read_double(fp, swap_flag, &header->z_add_offset); - fread(&header->x_units, sizeof(char[GRD_UNIT_LEN]), 1, fp); - fread(&header->y_units, sizeof(char[GRD_UNIT_LEN]), 1, fp); - fread(&header->z_units, sizeof(char[GRD_UNIT_LEN]), 1, fp); - fread(&header->title, sizeof(char[GRD_TITLE_LEN]), 1, fp); - fread(&header->command, sizeof(char[GRD_COMMAND_LEN]), 1, fp); - fread(&header->remark, sizeof(char[GRD_REMARK_LEN]), 1, fp); + if (fread(&header->x_units, sizeof(char[GRD_UNIT_LEN]), 1, fp) != 1) + G_fatal_error(_("Error reading data")); + if (fread(&header->y_units, sizeof(char[GRD_UNIT_LEN]), 1, fp) != 1) + G_fatal_error(_("Error reading data")); + if (fread(&header->z_units, sizeof(char[GRD_UNIT_LEN]), 1, fp) != 1) + G_fatal_error(_("Error reading data")); + if (fread(&header->title, sizeof(char[GRD_TITLE_LEN]), 1, fp) != 1) + G_fatal_error(_("Error reading data")); + if (fread(&header->command, sizeof(char[GRD_COMMAND_LEN]), 1, fp) != 1) + G_fatal_error(_("Error reading data")); + if (fread(&header->remark, sizeof(char[GRD_REMARK_LEN]), 1, fp) != 1) + G_fatal_error(_("Error reading data")); } static void get_gmt_header(const struct GRD_HEADER *header, diff --git a/raster/r.in.gridatb/file_io.c b/raster/r.in.gridatb/file_io.c index 1c2339fa0a5..76eb1b6b3fb 100644 --- a/raster/r.in.gridatb/file_io.c +++ b/raster/r.in.gridatb/file_io.c @@ -15,11 +15,14 @@ void rdwr_gridatb(void) fp = fopen(file, "r"); buf[0] = 0; - fscanf(fp, "%[^\n]", buf); + if (fscanf(fp, "%[^\n]", buf) != 1) + G_fatal_error(_("Error reading data")); if (!buf[0]) getc(fp); - fscanf(fp, "%d %d %lf\n", &cellhd.cols, &cellhd.rows, &cellhd.ns_res); + if (fscanf(fp, "%d %d %lf\n", &cellhd.cols, &cellhd.rows, &cellhd.ns_res) + != 3) + G_fatal_error(_("Error reading data")); cellhd.ew_res = cellhd.ns_res; cellhd.south = 0; cellhd.north = cellhd.south + cellhd.ns_res * cellhd.rows; @@ -52,7 +55,8 @@ void rdwr_gridatb(void) for (j = 0; j < cellhd.cols; j++) { idx = 9999.0; - fscanf(fp, "%f", &idx); + if (fscanf(fp, "%f", &idx) != 1) + G_fatal_error(_("Error reading data")); if (idx >= 9999.0) { Rast_set_f_null_value(&(cell[j]), 1); } diff --git a/raster/r.in.mat/main.c b/raster/r.in.mat/main.c index 0b6d6433c34..b882f4bb146 100644 --- a/raster/r.in.mat/main.c +++ b/raster/r.in.mat/main.c @@ -128,7 +128,8 @@ int main(int argc, char *argv[]) have_n = have_s = have_e = have_w = 0; /* Check Endian State of File */ - fread(&format_block, sizeof(int), 1, fp1); + if (fread(&format_block, sizeof(int), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); G_fseek(fp1, 0, SEEK_SET); /* frewind() */ file_endianness = format_block / 1000; /* 0=little, 1=big */ @@ -151,7 +152,8 @@ int main(int argc, char *argv[]) while (!feof(fp1)) { /* scan for needed array variables */ - fread(&format_block, sizeof(int), 1, fp1); + if (fread(&format_block, sizeof(int), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); if (feof(fp1)) break; @@ -169,25 +171,30 @@ int main(int argc, char *argv[]) /* 4 byte number of rows & columns */ - fread(&mrows, sizeof(int), 1, fp1); - fread(&ncols, sizeof(int), 1, fp1); + if (fread(&mrows, sizeof(int), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); + if (fread(&ncols, sizeof(int), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); if (mrows < 1 || ncols < 1) G_fatal_error(_("Array contains no data")); /* 4 byte real/imag flag 0=real vals only */ - fread(&realflag, sizeof(int), 1, fp1); + if (fread(&realflag, sizeof(int), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); if (realflag != 0) G_fatal_error(_("Array contains imaginary data")); /* length of array_name+1 */ - fread(&name_len, sizeof(int), 1, fp1); + if (fread(&name_len, sizeof(int), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); if (name_len < 1) G_fatal_error(_("Invalid array name")); /* array name */ for (i = 0; i < 64; i++) { - fread(&c, sizeof(char), 1, fp1); + if (fread(&c, sizeof(char), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); array_name[i] = c; if (c == '\0') break; @@ -205,10 +212,13 @@ int main(int argc, char *argv[]) if (mrows != 1 || ncols > 64 || data_type != 1) G_fatal_error(_("Invalid 'map_name' array")); - if (data_format == 5) - fread(&map_name, sizeof(char), ncols, fp1); + if (data_format == 5) { + if (fread(&map_name, sizeof(char), ncols, fp1) != ncols) + G_fatal_error(_("Error reading data")); + } else if (data_format == 0) { /* sigh.. */ - fread(&map_name_d, sizeof(double), ncols, fp1); + if (fread(&map_name_d, sizeof(double), ncols, fp1) != ncols) + G_fatal_error(_("Error reading data")); for (i = 0; i < ncols; i++) map_name[i] = (char)map_name_d[i]; } @@ -225,7 +235,8 @@ int main(int argc, char *argv[]) if (mrows != 1 || ncols != 1 || data_format != 0 || data_type != 0) G_fatal_error(_("Invalid 'map_northern_edge' array")); - fread(®ion.north, sizeof(double), 1, fp1); + if (fread(®ion.north, sizeof(double), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); G_debug(1, "northern edge=%f", region.north); } @@ -234,7 +245,8 @@ int main(int argc, char *argv[]) if (mrows != 1 || ncols != 1 || data_format != 0 || data_type != 0) G_fatal_error(_("Invalid 'map_southern_edge' array")); - fread(®ion.south, sizeof(double), 1, fp1); + if (fread(®ion.south, sizeof(double), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); G_debug(1, "southern edge=%f", region.south); } @@ -243,7 +255,8 @@ int main(int argc, char *argv[]) if (mrows != 1 || ncols != 1 || data_format != 0 || data_type != 0) G_fatal_error(_("Invalid 'map_eastern_edge' array")); - fread(®ion.east, sizeof(double), 1, fp1); + if (fread(®ion.east, sizeof(double), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); G_debug(1, "eastern edge=%f", region.east); } @@ -252,7 +265,8 @@ int main(int argc, char *argv[]) if (mrows != 1 || ncols != 1 || data_format != 0 || data_type != 0) G_fatal_error(_("Invalid 'map_western_edge' array")); - fread(®ion.west, sizeof(double), 1, fp1); + if (fread(®ion.west, sizeof(double), 1, fp1) != 1) + G_fatal_error(_("Error reading data")); G_debug(1, "western edge=%f", region.west); } @@ -261,10 +275,13 @@ int main(int argc, char *argv[]) if (mrows != 1 || ncols > 1023 || data_type != 1) G_fatal_error(_("Invalid 'map_title' array")); - if (data_format == 5) - fread(&map_title, sizeof(char), ncols, fp1); + if (data_format == 5) { + if (fread(&map_title, sizeof(char), ncols, fp1) != ncols) + G_fatal_error(_("Error reading data")); + } else if (data_format == 0) { /* sigh.. */ - fread(&map_name_d, sizeof(double), ncols, fp1); /* note reusing variable */ + if (fread(&map_name_d, sizeof(double), ncols, fp1) != ncols) /* note reusing variable */ + G_fatal_error(_("Error reading data")); for (i = 0; i < ncols; i++) map_title[i] = (char)map_name_d[i]; } @@ -291,21 +308,27 @@ int main(int argc, char *argv[]) map_type = DCELL_TYPE; array_data = G_calloc(mrows * (ncols + 1), Rast_cell_size(map_type)); - fread(array_data, sizeof(double), mrows * ncols, fp1); + if (fread(array_data, sizeof(double), (size_t)mrows * ncols, fp1) + != (mrows * ncols)) + G_fatal_error(_("Error reading data")); break; case 1: G_debug(1, " float map"); map_type = FCELL_TYPE; array_data = G_calloc(mrows * (ncols + 1), Rast_cell_size(map_type)); - fread(array_data, sizeof(float), mrows * ncols, fp1); + if (fread(array_data, sizeof(float), (size_t)mrows * ncols, fp1) + != (mrows * ncols)) + G_fatal_error(_("Error reading data")); break; case 2: G_debug(1, " int map"); map_type = CELL_TYPE; array_data = G_calloc(mrows * (ncols + 1), Rast_cell_size(map_type)); - fread(array_data, sizeof(int), mrows * ncols, fp1); + if (fread(array_data, sizeof(int), (size_t)mrows * ncols, fp1) + != (mrows * ncols)) + G_fatal_error(_("Error reading data")); break; default: G_fatal_error(_("Please contact the GRASS development team")); diff --git a/raster/r.param.scale/disp_matrix.c b/raster/r.param.scale/disp_matrix.c index dfba781caa4..2d4314aaa42 100644 --- a/raster/r.param.scale/disp_matrix.c +++ b/raster/r.param.scale/disp_matrix.c @@ -1,4 +1,6 @@ - +/* This file and its content is not used. */ +/* Could be removed at some point. */ +#if 0 /****************************************************************/ /* disp_matrix() Function to display the contents of */ /* the three matrices used in solving */ @@ -56,3 +58,4 @@ void disp_wind(CELL * z) fgets(dummy, 70, stdin); } +#endif diff --git a/raster/r.topmodel/file_io.c b/raster/r.topmodel/file_io.c index 90a7bbcc1d5..49ab89ec193 100644 --- a/raster/r.topmodel/file_io.c +++ b/raster/r.topmodel/file_io.c @@ -10,7 +10,8 @@ void get_line(FILE * fp, char *buffer) char *str; buffer[0] = 0; - fscanf(fp, "%[^\n]", buffer); + if (fscanf(fp, "%[^\n]", buffer) != 1) + G_fatal_error(_("Error reading data")); getc(fp); if ((str = (char *)strchr(buffer, '#'))) diff --git a/vector/v.vol.rst/user1.c b/vector/v.vol.rst/user1.c index 32d13e00907..2a04ac74f12 100644 --- a/vector/v.vol.rst/user1.c +++ b/vector/v.vol.rst/user1.c @@ -392,7 +392,7 @@ int INPUT(struct Map_info *In, char *column, char *scol, char *wheresql) int OUTGR() { void *cf1, *cf2, *cf3, *cf4, *cf5, *cf6, *cf7; - int read_val; + size_t read_val; FCELL *cell; float *data; int i, iarc, cnt; @@ -408,7 +408,11 @@ int OUTGR() G_fseek (Tmp_fd_cell, ((off_t) (nsizr - 1 - i) * nsizc * sizeof(FCELL)), 0); - fread(cell, sizeof(FCELL), nsizc, Tmp_fd_cell); + read_val = fread(cell, sizeof(FCELL), nsizc, Tmp_fd_cell); + if (read_val != nsizc) { + clean(); + G_fatal_error(_("Unable to read data from temp file")); + } Rast_put_f_row(fdcout, cell); } } From 2887572a54e55b6ad5bebdc4f45ef9cd95f8d585 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Mon, 7 Nov 2022 06:56:30 +0100 Subject: [PATCH 063/123] wxGUI: add r.buildvrt module into DevelopRasterMap toolbox (#2621) --- gui/wxpython/xml/toolboxes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gui/wxpython/xml/toolboxes.xml b/gui/wxpython/xml/toolboxes.xml index fb21827b5a0..c15615f0ca1 100644 --- a/gui/wxpython/xml/toolboxes.xml +++ b/gui/wxpython/xml/toolboxes.xml @@ -691,6 +691,9 @@ + + + From 7fb64dae0eb5e99161bf8b7819f320cc1b68ab1e Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Tue, 8 Nov 2022 23:21:31 +0100 Subject: [PATCH 064/123] Fix -Wsometimes-uninitialized compiler warnings (#2165) --- db/drivers/ogr/describe.c | 4 ++-- display/d.vect.thematic/main.c | 2 +- display/d.vect/opt.c | 2 +- imagery/i.eb.soilheatflux/g0.c | 2 +- lib/imagery/iscatt_structs.c | 2 +- lib/raster3d/getblock.c | 2 +- lib/vector/Vlib/build_pg.c | 2 +- raster/r.buffer/main.c | 2 +- raster/r.fill.stats/main.c | 4 ++-- raster/r.resamp.rst/main.c | 2 +- raster3d/r3.in.bin/main.c | 2 +- raster3d/r3.in.v5d/v5d.c | 6 +++--- raster3d/r3.out.bin/main.c | 2 +- raster3d/r3.out.v5d/v5d.c | 6 +++--- vector/v.normal/main.c | 2 +- vector/v.proj/main.c | 2 +- vector/v.sample/main.c | 2 +- vector/v.to.rast3/main.c | 2 +- 18 files changed, 24 insertions(+), 24 deletions(-) diff --git a/db/drivers/ogr/describe.c b/db/drivers/ogr/describe.c index 8c2688575b0..bf1ce160a30 100644 --- a/db/drivers/ogr/describe.c +++ b/db/drivers/ogr/describe.c @@ -162,8 +162,8 @@ int describe_table(OGRLayerH hLayer, dbTable ** table, cursor * c) } for (i = 0; i < ncols; i++, col++) { - int sqlType; - int size, precision, scale; + int sqlType = DB_SQL_TYPE_UNKNOWN; + int size = 0, precision = 0, scale; hFieldDefn = OGR_FD_GetFieldDefn(hFeatureDefn, i); ogrType = OGR_Fld_GetType(hFieldDefn); diff --git a/display/d.vect.thematic/main.c b/display/d.vect.thematic/main.c index 21062d35d7a..1d8336aee4e 100644 --- a/display/d.vect.thematic/main.c +++ b/display/d.vect.thematic/main.c @@ -66,7 +66,7 @@ int main(int argc, char **argv) int *cats, ncat, nrec, ctype; struct Map_info Map; struct field_info *fi; - dbDriver *driver; + dbDriver *driver = NULL; dbHandle handle; dbCatValArray cvarr; struct Cell_head window; diff --git a/display/d.vect/opt.c b/display/d.vect/opt.c index a58886936ae..fcb9b02d7fe 100644 --- a/display/d.vect/opt.c +++ b/display/d.vect/opt.c @@ -109,7 +109,7 @@ void options_to_lattr(LATTR *lattr, const char *layer, int option_to_color(struct color_rgb *color, const char *color_val) { - int has_color, ret; + int has_color = 0, ret; int r, g, b; ret = G_str_to_color(color_val, &r, &g, &b); diff --git a/imagery/i.eb.soilheatflux/g0.c b/imagery/i.eb.soilheatflux/g0.c index 6c4571f89b2..c43ba256231 100644 --- a/imagery/i.eb.soilheatflux/g0.c +++ b/imagery/i.eb.soilheatflux/g0.c @@ -6,7 +6,7 @@ double g_0(double bbalb, double ndvi, double tempk, double rnet, double time, int roerink) { double a, b, result; - double r0_coef; + double r0_coef = 1.1; if (time <= 9.0 || time > 15.0) r0_coef = 1.1; diff --git a/lib/imagery/iscatt_structs.c b/lib/imagery/iscatt_structs.c index 638f84d4423..d4d8117718d 100644 --- a/lib/imagery/iscatt_structs.c +++ b/lib/imagery/iscatt_structs.c @@ -154,7 +154,7 @@ void I_sc_free_cats(struct scCats *cats) */ int I_sc_add_cat(struct scCats *cats) { - int i_scatt, i_cat_id, cat_id; + int i_scatt, i_cat_id, cat_id = 0; int n_a_cats = cats->n_a_cats; if (cats->n_a_cats >= cats->n_cats) diff --git a/lib/raster3d/getblock.c b/lib/raster3d/getblock.c index 884c6d03d5b..2e03a92a9ec 100644 --- a/lib/raster3d/getblock.c +++ b/lib/raster3d/getblock.c @@ -12,7 +12,7 @@ void Rast3d_get_block_nocache(RASTER3D_Map * map, int x0, int y0, int z0, int nx, int ny, int nz, void *block, int type) { - void *tile; + void *tile = NULL; int tileX0, tileY0, tileZ0, tileOffsX0, tileOffsY0, tileOffsZ0; int tileX1, tileY1, tileZ1, tileOffsX1, tileOffsY1, tileOffsZ1; int tx, ty, tz, dx, dy, dz, x, y, z, rows, cols, depths; diff --git a/lib/vector/Vlib/build_pg.c b/lib/vector/Vlib/build_pg.c index 965c95798d7..9a00c89095b 100644 --- a/lib/vector/Vlib/build_pg.c +++ b/lib/vector/Vlib/build_pg.c @@ -142,7 +142,7 @@ int Vect_build_pg(struct Map_info *Map, int build) */ int build_topo(struct Map_info *Map, int build) { - int line, type, s, n_nodes; + int line, type, s, n_nodes = 0; int area, nareas, isle, nisles; int face[2]; char stmt[DB_SQL_MAX]; diff --git a/raster/r.buffer/main.c b/raster/r.buffer/main.c index 28aa87ab08e..e481aabe7c6 100644 --- a/raster/r.buffer/main.c +++ b/raster/r.buffer/main.c @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) struct Distance *pd; const char *input, *output, *mapset; char **zone_list; - double to_meters; + double to_meters = 1.0; const char *units; int offset; int count; diff --git a/raster/r.fill.stats/main.c b/raster/r.fill.stats/main.c index 1f5a7a734ca..4339e42c4b1 100644 --- a/raster/r.fill.stats/main.c +++ b/raster/r.fill.stats/main.c @@ -1073,8 +1073,8 @@ int main(int argc, char *argv[]) } } } - char *data_type_string_in; - char *data_type_string_out; + char *data_type_string_in = NULL; + char *data_type_string_out = NULL; if (IN_TYPE == CELL_TYPE) { data_type_string_in = "integer"; diff --git a/raster/r.resamp.rst/main.c b/raster/r.resamp.rst/main.c index d50e3b69df4..1f7ab01d4cd 100644 --- a/raster/r.resamp.rst/main.c +++ b/raster/r.resamp.rst/main.c @@ -126,7 +126,7 @@ int main(int argc, char *argv[]) { int m1; struct FPRange range; - DCELL cellmin, cellmax; + DCELL cellmin = 0.0, cellmax; FCELL *cellrow, fcellmin; struct GModule *module; diff --git a/raster3d/r3.in.bin/main.c b/raster3d/r3.in.bin/main.c index 9fc9e043753..ee5e2e8f6c3 100644 --- a/raster3d/r3.in.bin/main.c +++ b/raster3d/r3.in.bin/main.c @@ -252,7 +252,7 @@ int main(int argc, char *argv[]) int is_integer; int is_signed; int bytes; - int order; + int order = 0; int byte_swap; RASTER_MAP_TYPE map_type; off_t file_size; diff --git a/raster3d/r3.in.v5d/v5d.c b/raster3d/r3.in.v5d/v5d.c index 515960403eb..5e2e2fcf43d 100644 --- a/raster3d/r3.in.v5d/v5d.c +++ b/raster3d/r3.in.v5d/v5d.c @@ -2029,7 +2029,7 @@ v5dstruct *v5dOpenFile(const char *filename, v5dstruct * v) int v5dReadCompressedGrid(v5dstruct * v, int time, int var, float *ga, float *gb, void *compdata) { - int pos, n, k; + int pos, n, k = 0; if (time < 0 || time >= v->NumTimes) { printf("Error in v5dReadCompressedGrid: bad timestep argument (%d)\n", @@ -2097,7 +2097,7 @@ int v5dReadGrid(v5dstruct * v, int time, int var, float data[]) { float ga[MAXLEVELS], gb[MAXLEVELS]; void *compdata; - int bytes; + int bytes = 0; if (time < 0 || time >= v->NumTimes) { printf("Error in v5dReadGrid: bad timestep argument (%d)\n", time); @@ -2490,7 +2490,7 @@ int v5dWriteGrid(v5dstruct * v, int time, int var, const float data[]) { float ga[MAXLEVELS], gb[MAXLEVELS]; void *compdata; - int n, bytes; + int n, bytes = 0; float min, max; if (v->Mode != 'w') { diff --git a/raster3d/r3.out.bin/main.c b/raster3d/r3.out.bin/main.c index c80e1f48f10..ef863bee19f 100644 --- a/raster3d/r3.out.bin/main.c +++ b/raster3d/r3.out.bin/main.c @@ -208,7 +208,7 @@ int main(int argc, char *argv[]) char *outfile; double null_val; int do_stdout; - int order; + int order = 0; int swap_flag; int bytes; int as_integer = 0; diff --git a/raster3d/r3.out.v5d/v5d.c b/raster3d/r3.out.v5d/v5d.c index 4ba3327c5b4..460fd991fba 100644 --- a/raster3d/r3.out.v5d/v5d.c +++ b/raster3d/r3.out.v5d/v5d.c @@ -2027,7 +2027,7 @@ v5dstruct *v5dOpenFile(const char *filename, v5dstruct * v) int v5dReadCompressedGrid(v5dstruct * v, int time, int var, float *ga, float *gb, void *compdata) { - int n, k; + int n, k = 0; off_t pos; if (time < 0 || time >= v->NumTimes) { @@ -2096,7 +2096,7 @@ int v5dReadGrid(v5dstruct * v, int time, int var, float data[]) { float ga[MAXLEVELS], gb[MAXLEVELS]; void *compdata; - int bytes; + int bytes = 0; if (time < 0 || time >= v->NumTimes) { printf("Error in v5dReadGrid: bad timestep argument (%d)\n", time); @@ -2491,7 +2491,7 @@ int v5dWriteGrid(v5dstruct * v, int time, int var, const float data[]) { float ga[MAXLEVELS], gb[MAXLEVELS]; void *compdata; - int n, bytes; + int n, bytes = 0; float min, max; if (v->Mode != 'w') { diff --git a/vector/v.normal/main.c b/vector/v.normal/main.c index 160eee044fb..d9f9fcb2072 100644 --- a/vector/v.normal/main.c +++ b/vector/v.normal/main.c @@ -153,7 +153,7 @@ int main(int argc, char **argv) nsites = 0; for (line = 1; line <= nlines; line++) { int type, cat, ret, cval; - double dval; + double dval = 0.0; G_debug(3, "line = %d", line); diff --git a/vector/v.proj/main.c b/vector/v.proj/main.c index 82c0d38b624..2061d126ed2 100644 --- a/vector/v.proj/main.c +++ b/vector/v.proj/main.c @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) #ifdef HAVE_PROJ_H struct Option *pipeline; /* name of custom PROJ pipeline */ #endif - struct Key_Value *in_proj_keys, *in_unit_keys; + struct Key_Value *in_proj_keys = NULL, *in_unit_keys = NULL; struct Key_Value *out_proj_keys, *out_unit_keys; struct line_pnts *Points, *Points2; struct line_cats *Cats; diff --git a/vector/v.sample/main.c b/vector/v.sample/main.c index 6702ffdbc4c..f09a1c45008 100644 --- a/vector/v.sample/main.c +++ b/vector/v.sample/main.c @@ -205,7 +205,7 @@ int main(int argc, char **argv) nlines = Vect_get_num_lines(&In); for (line = 1; line <= nlines; line++) { - int type, cat, ret, cval; + int type, cat = -1, ret, cval; double dval; G_debug(3, "line = %d", line); diff --git a/vector/v.to.rast3/main.c b/vector/v.to.rast3/main.c index 0a117af8cfd..05383064bdc 100644 --- a/vector/v.to.rast3/main.c +++ b/vector/v.to.rast3/main.c @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) nlines = Vect_get_num_lines(&Map); for (line = 1; line <= nlines; line++) { - int type, cat, depth, row, col, ret; + int type, cat, depth, row, col, ret = DB_FAILED; double value; G_percent(line, nlines, 2); From 7b21df15e51ba97d7399a16167fd3ff840ef3597 Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Wed, 9 Nov 2022 23:34:41 +0100 Subject: [PATCH 065/123] Fix -Wuninitialized compiler warnings (#2164) --- imagery/i.gensig/means.c | 6 ++---- lib/raster3d/test/test_put_get_value_large_file.c | 3 ++- lib/rst/interp_float/ressegm2d.c | 2 +- lib/rst/interp_float/segmen2d_parallel.c | 2 +- lib/vector/Vlib/ascii.c | 2 +- lib/vector/Vlib/net_build.c | 2 +- lib/vector/neta/path.c | 2 +- raster/r.statistics/o_sum.c | 3 +-- raster/r.stream.extract/streams.c | 7 +++---- vector/v.lrs/v.lrs.label/main.c | 2 +- vector/v.net.salesman/main.c | 4 ++-- vector/v.split/main.c | 3 ++- 12 files changed, 18 insertions(+), 20 deletions(-) diff --git a/imagery/i.gensig/means.c b/imagery/i.gensig/means.c index c0c72fd6a58..5df6bdd6f7a 100644 --- a/imagery/i.gensig/means.c +++ b/imagery/i.gensig/means.c @@ -9,7 +9,7 @@ int compute_means(struct files *files, struct Signature *S) { - int n, n_nulls; + int n; int b; int nrows, ncols, row, col; CELL *class; @@ -32,10 +32,8 @@ int compute_means(struct files *files, struct Signature *S) Rast_get_d_row(files->band_fd[b], cell = files->band_cell[b], row); for (col = 0; col < ncols; col++) { - if (Rast_is_d_null_value(&cell[col])) { - n_nulls++; + if (Rast_is_d_null_value(&cell[col])) continue; - } n = class[col]; if (n < 0) continue; diff --git a/lib/raster3d/test/test_put_get_value_large_file.c b/lib/raster3d/test/test_put_get_value_large_file.c index fc2c2dba577..b8324dd4709 100644 --- a/lib/raster3d/test/test_put_get_value_large_file.c +++ b/lib/raster3d/test/test_put_get_value_large_file.c @@ -444,7 +444,8 @@ int test_large_file_sparse_random(int depths, int rows, int cols, for (x = 0; x < region.cols; x++) { /* Check the counter as cell value */ Rast3d_get_value(map, x, y, z, &value, DCELL_TYPE); - if (fabs(value - random_value_vector[i]) > EPSILON) { + random_value = random_value_vector[i]; + if (fabs(value - random_value) > EPSILON) { G_message ("At: z %i y %i x %i -- value %.14lf != %.14lf\n", z, y, x, value, random_value); diff --git a/lib/rst/interp_float/ressegm2d.c b/lib/rst/interp_float/ressegm2d.c index 7198a388f41..11ec74ea637 100644 --- a/lib/rst/interp_float/ressegm2d.c +++ b/lib/rst/interp_float/ressegm2d.c @@ -81,7 +81,7 @@ int IL_resample_interp_segments_2d(struct interp_params *params, struct BM *bitm double xmax, xmin, ymax, ymin; int totsegm; /* total number of segments */ int total_points = 0; - struct triple triple; /* contains garbage */ + struct triple triple = { 0.0, 0.0, 0.0, 0.0 }; /* contains garbage */ xmin = params->x_orig; diff --git a/lib/rst/interp_float/segmen2d_parallel.c b/lib/rst/interp_float/segmen2d_parallel.c index cde18948d4a..75ddb6ca462 100644 --- a/lib/rst/interp_float/segmen2d_parallel.c +++ b/lib/rst/interp_float/segmen2d_parallel.c @@ -49,7 +49,7 @@ int IL_interp_segments_2d_parallel(struct interp_params *params, struct tree_inf double dnorm, int threads) { int some_thread_failed = 0; - int tid; + int tid = 0; int i = 0; int j = 0; int i_cnt; diff --git a/lib/vector/Vlib/ascii.c b/lib/vector/Vlib/ascii.c index 5f4c2401243..695d4ac91b2 100644 --- a/lib/vector/Vlib/ascii.c +++ b/lib/vector/Vlib/ascii.c @@ -542,7 +542,7 @@ int Vect_write_ascii(FILE * ascii, if (columns) { for (i = 0; columns[i]; i++) { if (db_select_value - (driver, Fi->table, Fi->key, cat, columns[i], &value) < 0) + (driver, Fi->table, Fi->key, 0, columns[i], &value) < 0) G_fatal_error(_("Unable to select record from table <%s> (key %s, column %s)"), Fi->table, Fi->key, columns[i]); if (columns[i]) diff --git a/lib/vector/Vlib/net_build.c b/lib/vector/Vlib/net_build.c index 38e21886256..89ad1ef1125 100644 --- a/lib/vector/Vlib/net_build.c +++ b/lib/vector/Vlib/net_build.c @@ -79,7 +79,7 @@ Vect_net_ttb_build_graph(struct Map_info *Map, struct bound_box box; struct boxlist *List; - dglInt32_t dgl_cost = cost; + dglInt32_t dgl_cost; /*TODO attributes of turntable should be stored in one place */ const char *tcols[] = { "cat", "ln_from", "ln_to", "cost", "isec", NULL diff --git a/lib/vector/neta/path.c b/lib/vector/neta/path.c index 4e917e7becd..7e8e9fab16b 100644 --- a/lib/vector/neta/path.c +++ b/lib/vector/neta/path.c @@ -273,7 +273,7 @@ int NetA_find_path(dglGraph_s * graph, int from, int to, int *edges, prev[from] = NULL; while (begin != end) { dglInt32_t vertex = queue[begin++]; - dglInt32_t *edge, *node; + dglInt32_t *edge = NULL, *node; if (vertex == to) break; diff --git a/raster/r.statistics/o_sum.c b/raster/r.statistics/o_sum.c index 119b8c87fa4..35530369d23 100644 --- a/raster/r.statistics/o_sum.c +++ b/raster/r.statistics/o_sum.c @@ -13,7 +13,6 @@ int o_sum(const char *basemap, const char *covermap, const char *outputmap, { long catb, basecat, covercat; double x, area, sum1; - int stat; struct Popen stats_child, reclass_child; FILE *stats, *reclass; @@ -44,7 +43,7 @@ int o_sum(const char *basemap, const char *covermap, const char *outputmap, G_popen_close(&stats_child); G_popen_close(&reclass_child); - return stat; + return 0; } static void sum_out(FILE * fp, long cat, double sum1) diff --git a/raster/r.stream.extract/streams.c b/raster/r.stream.extract/streams.c index cd1210360ea..1f227fa5ee6 100644 --- a/raster/r.stream.extract/streams.c +++ b/raster/r.stream.extract/streams.c @@ -70,7 +70,7 @@ static int continue_stream(CELL stream_id, int r_max, int c_max, /* debug */ if (n_stream_nodes != *stream_no) G_warning(_("Stream_no %d and n_stream_nodes %" PRI_OFF_T - " out of sync"), *stream_no, n_stream_nodes); + " out of sync"), *stream_no, n_stream_nodes); stream_node[*stream_no].n_alloc += 2; new_size = stream_node[*stream_no].n_alloc * sizeof(int); @@ -151,7 +151,7 @@ int do_accum(double d8cut) int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 }; int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 }; int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 }; - GW_LARGE_INT workedon, killer; + GW_LARGE_INT killer; char *flag_nbr; POINT astarpoint; WAT_ALT wa; @@ -331,7 +331,6 @@ int do_accum(double d8cut) } else if (ct_dir == np_side) { /* check for consistency with A * path */ - workedon++; } } } @@ -660,7 +659,7 @@ int extract_streams(double threshold, double mont_exp, int internal_acc) /* debug */ if (n_stream_nodes != stream_no) G_warning(_("Stream_no %d and n_stream_nodes %" PRI_OFF_T - " out of sync"), stream_no, n_stream_nodes); + " out of sync"), stream_no, n_stream_nodes); } /*********************/ diff --git a/vector/v.lrs/v.lrs.label/main.c b/vector/v.lrs/v.lrs.label/main.c index f4a4ef9461e..d5b120ea388 100644 --- a/vector/v.lrs/v.lrs.label/main.c +++ b/vector/v.lrs/v.lrs.label/main.c @@ -294,7 +294,7 @@ int main(int argc, char **argv) /* For each line select all existeng reference segments, sort them along the line * and fcreate stationing. */ - G_debug(2, "find_line(): lfield = %d lcat = %d", lfield, lcat); + G_debug(2, "find_line(): lfield = %d", lfield); arseg = 1000; rseg = (RSEGMENT *) G_malloc(arseg * sizeof(RSEGMENT)); diff --git a/vector/v.net.salesman/main.c b/vector/v.net.salesman/main.c index 2dee43b6ec7..183e7ab2149 100644 --- a/vector/v.net.salesman/main.c +++ b/vector/v.net.salesman/main.c @@ -500,8 +500,8 @@ int main(int argc, char **argv) /* tmpcost must always be > 0 */ - G_debug(2, "? %d - %d cost = %f x %f", node1, node2, tmpcost, - cost); + G_debug(2, "? %d - %d cost = %f x %f", cities[cycle[j]], + cities[cycle[j + 1]], tmpcost, cost); /* always true for j = 0 */ if (tmpcost < cost) { city1 = j; diff --git a/vector/v.split/main.c b/vector/v.split/main.c index 80378b5062b..49df7684aaa 100644 --- a/vector/v.split/main.c +++ b/vector/v.split/main.c @@ -237,9 +237,10 @@ int main(int argc, char *argv[]) if (nosplit) Vect_reset_line(Points3); + double x = 0.0, y = 0.0, z = 0.0; + for (i = 0; i < n; i++) { int ret; - double x, y, z; if (i == n - 1) { to = l; /* to be sure that it goes to end */ From 173ae70ec5fe4f7c452c53f90d786447368a2ac4 Mon Sep 17 00:00:00 2001 From: Stefan Blumentrath Date: Thu, 10 Nov 2022 23:32:32 +0100 Subject: [PATCH 066/123] v.in.ogr: skip columns with unsupported data type instead of failing to import (#2630) * skip binary columns * remove copied comment * indent + warning message * handle all unsupported column types with d-flag * remove second warning * Update vector/v.in.ogr/main.c Co-authored-by: Markus Metz <33666869+metzm@users.noreply.github.com> * implement suggestion from review * cleanup from review * simplify warning Co-authored-by: Markus Metz <33666869+metzm@users.noreply.github.com> --- vector/v.in.ogr/main.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/vector/v.in.ogr/main.c b/vector/v.in.ogr/main.c index 5563fd6ac29..e8197cea745 100644 --- a/vector/v.in.ogr/main.c +++ b/vector/v.in.ogr/main.c @@ -1053,8 +1053,8 @@ int main(int argc, char *argv[]) if (key_idx[layer] > -1 && key_idx[layer] == i) continue; /* skip defined key (FID column) */ - i_out++; - + i_out++; + Ogr_field = OGR_FD_GetFieldDefn(Ogr_featuredefn, i); Ogr_ftype = OGR_Fld_GetType(Ogr_field); @@ -1175,13 +1175,14 @@ int main(int argc, char *argv[]) Ogr_fieldname, OFTIntegerListlength); } else { - G_warning(_("Column type (Ogr_ftype: %d) not supported (Ogr_fieldname: %s)"), - Ogr_ftype, Ogr_fieldname); - buf[0] = 0; - col_info[i_out].type = G_store(buf); - } - G_free(Ogr_fieldname); - } + /* handle columns of unsupported data type */ + G_warning(_("Column <%s> of unsupported data type \"%s\" is omitted from import"), + Ogr_fieldname, OGR_GetFieldTypeName(Ogr_ftype)); + i_out--; + ncols_out--; + } + G_free(Ogr_fieldname); + } /* fix duplicate column names */ done = 0; @@ -1388,10 +1389,6 @@ int main(int argc, char *argv[]) db_double_quote_string(&strval); G_rasprintf(&sqlbuf, &sqlbufsize, ", '%s'", db_get_string(&strval)); } - else { - /* column type not supported */ - G_rasprintf(&sqlbuf, &sqlbufsize, "%c", '\0'); - } } else { /* G_warning (_("Column value not set" )); */ From ef15ddc160a05176f366a738e1edf69161a35472 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Thu, 10 Nov 2022 23:51:06 -0500 Subject: [PATCH 067/123] v.surf.rst: fix cross-validation and prevent running it multi-threaded (#2643) Bug introduced in #1271. --- vector/v.surf.rst/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vector/v.surf.rst/main.c b/vector/v.surf.rst/main.c index 0d5089ed2cd..32bbb920a03 100644 --- a/vector/v.surf.rst/main.c +++ b/vector/v.surf.rst/main.c @@ -419,6 +419,10 @@ int main(int argc, char *argv[]) G_warning(_("Parallel computation disabled when deviation output is required")); threads = 1; } + if (parm.cvdev->answer && threads > 1) { + G_warning(_("Parallel computation disabled when cross validation output is required")); + threads = 1; + } #if defined(_OPENMP) omp_set_num_threads(threads); #else @@ -427,6 +431,7 @@ int main(int argc, char *argv[]) #endif if (devi) { + create_devi = true; if (Vect_legal_filename(devi) == -1) G_fatal_error(_("Output vector map name <%s> is not valid map name"), devi); @@ -637,8 +642,6 @@ int main(int argc, char *argv[]) } db_begin_transaction(driver2); count = 1; - create_devi = true; - } ertot = 0.; From ec7e8a6249bc3cdb10e6332e41101830e14143ff Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Fri, 11 Nov 2022 00:12:13 -0500 Subject: [PATCH 068/123] wxGUI: BaseToolbar.OnTool needs to be explicitly defined (#2632) Fixes #2626 --- gui/wxpython/gui_core/toolbars.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/gui/wxpython/gui_core/toolbars.py b/gui/wxpython/gui_core/toolbars.py index c88c0b0aab5..28c02d3a795 100644 --- a/gui/wxpython/gui_core/toolbars.py +++ b/gui/wxpython/gui_core/toolbars.py @@ -87,7 +87,12 @@ class ToolbarController: - """Controller specialized for wx.ToolBar subclass.""" + """Controller specialized for wx.ToolBar subclass. + + Toolbar subclasses must delegate methods to controller. + Methods inherited from toolbar class must be delegated explicitly + and other methods can be delegated by @c __getattr__. + """ def __init__(self, classObject, widget, parent, toolSwitcher): """ @@ -372,6 +377,10 @@ def CreateTool(self, *args, **kwargs): """@copydoc ToolbarController::CreateTool()""" self.controller.CreateTool(*args, **kwargs) + def OnTool(self, event): + """@copydoc ToolbarController::OnTool()""" + self.controller.OnTool(event) + def __getattr__(self, name): return getattr(self.controller, name) @@ -416,6 +425,10 @@ def CreateTool(self, *args, **kwargs): """@copydoc ToolbarController::CreateTool()""" self.controller.CreateTool(*args, **kwargs) + def OnTool(self, event): + """@copydoc ToolbarController::OnTool()""" + self.controller.OnTool(event) + def __getattr__(self, name): return getattr(self.controller, name) From ea625abe9f6d4f85ca624fc9b15734cec1d20dab Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Sat, 12 Nov 2022 04:22:34 +0100 Subject: [PATCH 069/123] utils/g.html2man: don't show mobile TOC menu JS code on cli man page (#2639) --- utils/g.html2man/ghtml.py | 6 +- utils/g.html2man/testsuite/test_ghtml2man.py | 60 ++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 utils/g.html2man/testsuite/test_ghtml2man.py diff --git a/utils/g.html2man/ghtml.py b/utils/g.html2man/ghtml.py index 33edf3bf984..d2aee608089 100644 --- a/utils/g.html2man/ghtml.py +++ b/utils/g.html2man/ghtml.py @@ -233,6 +233,9 @@ def omit(allowed, tags): excluded = setify(excluded) +# Don't show mobile TOC menu JS code among

    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 z zZKQk#EX-xnLiYDCmULfx$v~XC$e%Z@s*^TmVr*QFUx36tL897?4u(K87`>3tWa!S6 z;FSO%Cg%Fba(DJ_2_oVIU7dKgz+33{&o9fcRP}07uzAH~c0dWd4EAuMGCwegbDBUD zb`gpj>*?YBP!%FxrbcIm6?zRktr2`QQ`Gt3Mn6`J=4N)h*sntLwILT=6OfSrfS%Cs zICnaV^$-vqLOe|v!9YR?)Qy-k$=;&$#buGuEIiGpe{AzA!#C~Wc!;eJHg+z6XN1d~ zjpFEU{75Y-69K5-snaQ#*tx=(Fvxgj(_Z4x5`VMu0DeWxfH;ZF48zF7OiYEpXNxY1 zO~~QzJIwYRC8#mDW2rV{M~LDRA`^s&nl8**qJNQf|BN*b4Ukz+)!_$o<(uNvFH)w7 zB}Savaq2ml=-M5}WLHwTh!OAVlP5Qe%3ul)g{Ow0A&CvgMDECjQ(4M*$WW=Dz(-u6 z0Z};_IN&b#xy1;Bfj3%tPE-j0rN?}WEP>=?%apN9hXsB-^DqbsNY$!mFo)whbowsb z4uIbA<#C9NgnJolYG$MR$-yhq|Mq6tOY7|SSgY8oIdH+cN6Ohq*~9i~c<*brIcCpd zI5G|NEXNea*eDx9%l*BIc;0q{1evuF?hBGS0tVc}uHnhmv_2GTBp zG8Q^h&&mlmhFC?z4-R1F%)lK3QIfn6!C63H1Eu`Fk>_;xfFKD~yz9QCA2!UPp7nBZ zgm{*y9j(v&`4KuC94n8}byoxPU%%^kA(pW?jsY^#athu;L*uQH-lVz%>NII^I`rxHBt=Q_^*cUV|nCJk{uRIwG+OaXn%!906rP8&e;j zhDEG+44>MT;sb*rxQ~47w#P|0W1QS(NMeLPnM2_dY-gASx94wK;2|ki!mRQUFEa;C znm;{49+4yaz1;S(U?T0hb?X*~!X51wj23`E2+0~g?i1*K8j%^=lKENqRCZRKm-m83i{*ZF&k{+D|SDYgX4!_p*WQY`wP1! z0Hez=zbElIS6|ck-e8RjKkCILQ1m>}U8ge;L)LYXfk!Q?68s!t7nXWwfVQtLP7fs_ zhU3F1CaVwv6Ov*AgEbhGtj3EkfJ2!&vPWv2S@z_aT%N@!nNu)&u1)f{TK^YcKVe4! zrEAyTHDuoY^_9fAhF=@}`STvGB#`u!I>=zx52+rJgJ%m+trdUeWtY}R5?&R^V zt}ax`KF1w#N@I?ZkB+GaDZTjk(yuTz$wLpfN6?xL7t|~X4kO`husWh8@oRQI&xAuP zaB`xN!@yeF*OX2+>88x_&x>a_pG`lqL|A_$^vq2|m9Lt{i-};}H%EI6%nO_u~2aCUZKsY#H zs1KMhR5}jJ86Wc~Kff=^HsG%b@-{nI6gQ%M{r+AR>m(tOeK{K`-f_qKqd%W zmy;>ZZ52$-rKQejWjHaiTAUw~CZQ?#=sm#i9~T^Yh87CSJRRJb09{C>>;U4BeBaFM ztn3GkY_2Ev7zDq7ZWspK71+%6@c6>ix;C7Se=(m;UKm^i)MSYuivaD6cBH106DBM) zC~im^->lE4Ba*)FS~GF^lYb{*Hf|&~Osq+?2IbMAk68};+uKQGQ994poO2$-AFgy3 z{?#mAHHKg*T05k0oe0jF%(Tvoc2! z1rz>*SWzG!Lk6S8D9G=GnhWqSJ>V@P$|SC%^NtLMLa)3%=LD8vRkGpL!v_wW3&QcT z{V*Hb6+FHVZQb4Bc=lq)K#YsBLx=GeN=KG^;K4?yt7SRZ>!Je`N65(zpf;g6W{UBa zFMCp;RdA0|h-Su*cZ!aVu8LE?rPpKg4;MiA@R1{(@%GchZ z?1y9MVHE)42jc{%-JA7x9Da_vxL};Tyu4ty9O{1Jx*{s9cS5HTfi(lem2pR;gA0nz zh@3m;j`1lo_A%HHuA@+hv!LpZ>;+>&$jQe?$;tj`J=B@9acZaY8XA<*{>m(^#**LD z6x10@pF>o}9cA({V5M?9L}f^1vn~i{VjjXpKt$b9nz1l@h-1vn7UcjJgSW8hVSU<6`WQr)vtZ2W6wCzSP*T-rD-)93bqwb&dCrJ|5YKWjc3e18^n2;HO;Z?M%w!fk zE)OBXAXg~MA+>kb{nJHWvyXBrSO?e#hMiyI}rPn~c!^15;oUpC%-+Wf*0X;e1<2a!TqMC&7dG&ss z=WnOgr$%+JsF*YLpUOFLE@V0 zD$Jx_Y8i@e?-d!51oaPZ!5kFYybz|L3yZdOZ46SKLGiUtR#c&SF6*XJu1;_sggDRh`PwG-C>n%7-||Cpqu zi*^w^Hgdr+UShB9Mni7Sy!p?^%9RLXocu!;dsx`0^MiPw;7|Vd7HWS0o;Ue|(SNys zy^{8(Qxomj=@k5iX?^9Ztq+CQ9X`pkIzY;+S~KH2?h?iCJU@2dd3VofzdW-?_UA2l zx{((_GtE!=C0kMNR$oyZ@ihG5BOy=Q@^|lS@7y*Edt>z0qRy?{Q7D*cz2;ljr?#^@ zrh;332%OToagz0~{%=PPZDH6|+Y;G=DdvO%Wf~^OM+*{&dVt=mgW(<^XhxGyyh~O z<*U}~OgH7_?J4;BDDC!$?Bfbm{{X(bgMu#}ZD{XOJe1RoCT$0+qO)7LwBB^Oe9<;~ z0f+ndS8ceGa@mI~=<0Fxz@G;%0N@Qa=oH^0gzGo_P8qF#mi1OJl2lYxu0$%RoU(uY zwfy9cgv5$p2TwdKWL3LWhe%(h(RgDnkM*3KoDYmrYs`7}C{@V3+A8?T(UoH-bBR~< zEj*{&Jx%)l%}v$wtIqIKW(ou7>TX+3y*qRE`uo;YMB>sPmT*54y4>8xO&42S&~_fi zuuM*Ocf+%C``$g53Ks;dZM_P6hOr#ZkKR#zResYmQa);9*@Zu~(@-Xx8sYI(#TM|(toBxPkvwGj`WpXH#i=OuYD!*Zor27U7#q#e)1!h z8MmfAw~E)|+bbR@n9n#H2jX683eUW>n3t4(yg>F@o8`;4Qc9A3 z>qzIjqBCtL?jzFB=5yI~@B!AY-@&B8mgxQCnta5El$0t~!=^*`(BD>OT)(>g$>J!t z$<~Xgpl7s7yTxLI6lXZy7R8y?uUkhO;+Q#a)5&^VWp+E2fya6*B-%ONH&#>cah&U= z4m4yf-e?Ivd~4R+$f@VN)lg$a%}}P^XexV6gyM-jo&kPK&Eca9`W>xbBJ2&hXcc4C zavZOxm=0yHxV2%|yUUTX;{(lZX1XObO2_Jt=HQg&%U@|EJvzDT&4&jo6qps>QJyef ziHY!%u>l+1!CN5cL}LmX#sc?|b|#r7fyVfZh>8MANb_}*(Hqg8M=AtF>SMZ_Mr}O& zgPGE+(>7@Sl2-bERec3ilv~?21|lG!q_ijv($WkiA>BxKmvj#vQ97g^*d@B9D%tm9fPz+vWj_OthWUvXauk2mO86U(v`buB|nT>@_BAvaFs zc6QTYge~KFxVWd@c9%mMZBVk&G9(a4gF#~;o+zG1GT3?R)FF{g$DX4KDeWiS@~Ot} zss%numPV?=l9mpKv_g{UY-VEyu z{2HwAoSV7Lft)uVc?_!(@V&XO33QC?qHgDp0S-dJ|2!@0C}3&zwM2$+OKnv2&{aCb z4i{_*X4~tkgs(TH&PP5dr3p(dwBo`_6735#voBd@z!{UQc6h3l$2i^KnK5~^%IUUj z4ZU#Y1U2-dqjS$C`Y1Sm%Vq+LO2Mzcz5Bd6VVXJ8CD7|fY|DwrqGhFYNMKG55!-;$ zwy4)vOGUD^_pEjQ1UHbs22g}5;mhnS{^x$lC**uX8#B1xwpsBSdsMF2u3&~67zYLL z?A8ACH*wW=w=ZayO_bV`vO&`?x209$BKRauO=bU-EzERT6ph=JyMNT!!bSIiPAel;;Fv^ z^lCZX=FxhSSS0U}vj|Uz?MwIFF=G*I*-SU+=onjO#Na{gA#`{y?Bw*iU&D*!#JH8j z?5F1~goNFQmpOXMb5E^8!W)bDN3PgCI}O`E@-|KcefB9Xc?oBI`D@e1-U+C=F-jrp z>A{Rk_pM4-5!0aSt=1|+DIlWzNKsc>VA!OhaFJ+ zO(cOqZ~Ri1#gndHWo8VJTfZlLiDkyKs0)69hC>iYyEzW}4?M*ODGR#`QrC}g1fCLp zS034LQ%F6fd}H?~GuabU&||Y72(*qjB2yoNu|a1Wjv3QqB~#YZv}k;u%7x?k9p{(? zCpKYO9CoJ^o9E|hS>_vrS2p1J1#Mm=uTyQ?NYQgp$UmIlso6>93xI~bUqu>;h5t(Q z@*&E$5#t6P_D5e$E=J^$`4F5PycZyL4Jk@3*&(ONs9Db{8HD>vP*68xwnE*i{%jpq z8A~WTNK0Ft7DSD#QFX%#QxZ@8D%NpmanI|6=x5BhJT9BfTBe$dle6lG=hx_AN;22= z?gB2`$&j7dCXBaT?ZZ3QO8N~@Q0ht?+qB3;sUnehQhCp-o#0C1c_Yp%e>L57UxQc8 z`xEnRNErDlvTHaaY2?L=!Thf1J}oj$KiqE!U%(^zNdc;zi4tRl@a&5U_ zB)2FyNd?*IXK2HN*`LzzQEA5a*6iJnX| zj~(&@Q`ckrZ(u-E{piWb!mk!dKv?IzXJ}j6uiO+M0mr>$j@kzD^7e-*o#)=ncwX>l zVe=kj-*G_M^$~j%rDzLv!1eFN45;M^^%hvfEiBPfPXht=jS(uI#H#ZN;EjiKtG`3l zr65(#ZPI^h{8K@0-rW{{8F2h8n)(ZeY5Rw3!Mh~$2AesT!*)&plPUr*1!VAI%=f*E zyYRezq*eUBvlKqXsh&Ety5j+m6d}rM4-Dsb^GF=_VKd@QiR5Dob8HI6od)&~Na7&op?H`;Oy+0O0=5p+=jv?tod7 zjd@wn`{8PL#;wmPA~>4r-ra1R@YUb^AJ$dE8oGC|v9i3YEYU`fPF6-?RqdS}_dcAj zb8cRawzLdH9j^4^A8$)cf_5m1N=V6onmYT;!NhSuuSD-)=S+0JZTdpL(Qh*U{K|hY z7)pK2`*T)?8Y(siX^QAozdJq;V;M|LP#nH&e~Pqn>^IcV{PXMP8y?>DJ;`s9j{sQ5F&+D;=3C zHpS~yv5|o|zez2_wEoL4f#aZ+ljS{sl?DR^~abNdsnHjJnE*dL2__`Y2 zbLIw!B)nnK9$fuBrf}my#^*Hi=$oc7_9+IXoU>$4(^a7LpDcl|&hXro{R*>n!Y^_} zEGkX5nr?!W;=!LlMm0rnBP$p}=`Sw+lZfe46^P!RnyGh94LaEx$yxFxbauA@D9y&K z4PV~(sS9nwF90gwG+*baZ@h(ofek#^kHxZwJ}~khbUY&?>mACL@y>SNdg6HpHQA2l z-xWNP!B19O0-u)ZH_0j3vx3=V7OQx3>J<{`a`B8UtzYicgDZ&NsV7sO+oLg{mC5-F zscSgfeMVhI!%>b7>LiU~m48y+*r7e8rbeD|L+67@M+yK+3G@t&SB@C=_UT3whZpOr zZr->4%$kMqrWfItr`J!7jHrdDX8_cKed&p@p=sEYR~7oMzsGt-3f6a*a0CTYz()soQTevQ_5Ta>3_yH0!@}m< z82;;%JN|%=h$zep491H~4d^A5ST@Kd4a)qmzHdUtgZ*8+N^Ev>FlOT1%kuX*Zi$k- zSGzhdsutEvecbuC_kM!}`o@_!HE=sdf0EGGXVonshAYWvXguWPRK4V_2$;jOp3EYZ z5}DxyJwWn!TURu2zyCt!@vd4j3yVxMf^o@}?-zDzXTNKNF22{(8Elfbq6!Xj0R<1i zXj@;Al^LY$Z?!+RG9Dk6(BF{~R|as|1w0S#V_~`5j=u!13T`CCi5mQilS_A$-{$k; zksmh>Qx({^KJKc7l&h>fcwG5;CfM%(Pz z6p14L@M8U`CX43Fbz=^2!CE{2k^!0^Gpn==PbNC!n@8j(g@{KQ&F$4g!u+kZzA#Nh z))4J~HnZ`faHS${pE)$lg9DxeC$aF4xnPAQ{s|~HTP9h$a2phxg>qlB=cN4P_i^8P zgvI*4l1EAxfper=@7=FG~3l389XgfCZegpmwG_ zf!@$h(B%hon7l*_Fc$Wk*NFYvy1x;h%@M2Qy+xmE`Ks;4zPm=xjvgJYlxV$HzpgKo zAI$PSEvl=^eg!bAb~+p#Z=Fh5EoX*yG!?{j>lB_Q=o(bMp9k<^eCoV=bO-hhBb|{G zByL}OiC8Mx*I(dljkitr3%hm&x5I)xc4oTvX#(+sAH|$wpT=e+J)3= z_~5w~nfMQy{bUWLRG#^k#GJ$zd$5X?DIDS9--V{4zkHEOvHCStZPzzZv6ReVB1}H! z^xdGL1~ywDmvjFG8?RD8?hEe~T^(JMgci5tcT)^jK+-W6P+|snC=9@>|a4 z6gsA-DFBp*kI&QI)e$$E^^nK0y}0gZV?2+<7w_Rv@w+8LcLR|5@n&nxxh_+bZD4?Z zVk(mn%R(-(J@+F{o>B(=dAF*M`(FBn{{vcDYgySrm0XQ?osm?bbufX{S_fqL5#BfN zQ|ym92}D(^0}o=|QA^xI2N;_c92yFMQo&$OAXC&gl_{4QXY(7pCGhd^&RCqi!zFM( zuE;0N&wo9?$d*874vC8BAB9Hr*bPK%PzX7HLfjZ2*T9&cY@avHDI9FSQG{?@P1Ac^ zddu2u*~lU=h4~Waxq{e|^zqIJxhEgrBWQ}tW9OrfxeBSAanL5;3eVenv)&Cj-^?%1 zDfkH$G&Bg87!=X|?mpu%czR-}k7 zimagv+VOAV4}dG64g7hJFnItD&up)QMdYDKOpb6IV7hI>5TL%11EAMQ06Ft*_(sqs zchj}EFT>6KO6QSWg^sds^9u{<1sSXT{iFFBp=TI?Rt6O?F*+Oy*R8hQXFTTAE;CwM zKOg|h{asA3GCW1U(G5oFdpf_RjscJTS)w$ghHx~fv7hT%DH_jLZIa79gQGIEQpN1; zpOlskyw}kq)oeaLe?Pl7@ekDBXQWKo2|Su0(AGXTpmmyrFuv%&`#X8i0cy|1LQWOj z1*qW#HWt>dV<~`0%N?#fva(->MupKbGk?nO4k0=8;!GbsAdS;jP#{cTjt7lk4C<#f z#P^K)#qvPsCA$YgVoW`V+6^M{}b zT19n)j}~aQtqUsNI86<}f8g4;3_Z9~6E4&&Xf16*2H%+bQ5Y(TtPxA;8#sHqF3DDg zYW4sA?Tt^I7^n)9&SmJW{_$fua;yZ*U*&0ThA;)?1L(QZtP6O_AHU<=Qt$y(h&RI3 z3gkHVf*Xg4>D?WIlwMre$fT|`D{kl9XQ}huGhCD+^F31q>IDjHA>a{^C`x=yD!8o< z2nGp2_>uEE@-TOjD8et_fWLyzD5C)W`Ya~qhs{x<>WVUpNcLsFbpX&X0#n<^gC&ML zt0GWd-KATB@$#1r!MIoPs@aA=#bL2-lFVH0n$Si2hjJ+!w&-M6SKM~965!)T{H}u0 z#8TmY*=E$s1v9>`zbNmdFb!{BT~vUgel*_@N8UADVMmCUKC#D0*=%jM38d79gEnTO z-T|Wss`nezlB5O@MSbC>de0o~vr@1LkTx0kxC7BhnTE&TVv?ycD`YjMu8+q~>#0FQ zo%a#3r7d@T(;Vy~JjrEw-5Ges@u)t3SXj&%-7(U2Fs-x*I`p~Z`Gk|o>v{`)ykKJT z5SLzk3{=qhBmCnelT%c zB6GxNd_s+IBl1UJoz9+o72{Fqy8P$f9R`6W2`=xpv5kT!2$zD!rEcOy+? zztRcdn*rlYITov8emu4Z1ZyV1u0iqJkuOBTF#i3WS!Wbw*Yy?N{y{-o(8=w(6Vx;x zwULvjoe^|;HW{*TcepDDN6(+`2m$W>GmYdU^(LRiUbB!ACI8Zk`Wsw z)kgjzs8Jid!Smf9{k%c(^K4Oa;Mlli>P#lXzunH;EiPPJi*rl^3Kthx<&Jl{_U}zi zCheLheb9>p&J2G!Wa*xnnZxf00ax#*hff*0THSW0W5AP+D0k33_^zL*YN)EJx;$q;*PPZ64;$1x|%um7ygj^)&^d(iTcV*_5X z?yDshNsV-(YJ700k2hhabqh;z)_ecFuy?>#tMVa=C$Y@5nJ&LKhfMhm`q+Io-O=u) zubxCF$L*6np|8542?l?1y8HW2)LG#nN_FIcD22(W=83KQF8P>Q2q0K^Mr8H@$2VHK z)R)jl!tGwMw^iyKhXx$RQfH0^IAv*=8-MZ&&O9%sZR8S)x+7C-_t~^Y^Bq`Um#Czs z5|C3SEcoD2K|sX-v43AnW>+*iZU=@jnwZ!~X}s+}TWzky#@aUKEwDvVBU`xR;m^Uk;Qg zMdB?*tTy^@MQ=;H<`Ck|o976HvPuXMI#BL$p8j0}6X-ci$5P=9XKD>vip3?xBaP*P zY`kpF^g$X2jBlGi7z9>aX%Tj;pBwT@wX6#g0U14))Kr|I9vNlAq3O{1&!6oJF*YmD zQZGqHNox7%*-Nx!6dtv?jP!DIz1%@QQ}0!}`#cG%*YxjX2k{Shb_!laP8t%Fi4$a; zVpfuf#&HYcE}kUh3;+#OKr(9E6MAa9#ceYYo%+sorrDJQv`LnaBs~v#Ndb$~E%0BM z*{S;&9RY%yR=`gCgZG0OyGdGFKC(ah3^@TF8G(QU{FANKxec~649ebrm5ww|dXHhZ zz*>oax_rbxOD2Ryu@;9GE9g|}UuJ-y(0IhTH+4X|v9kTetPrx&egLr?l0uEj*E+n@%$@!nCou3FI$any`8G$R0%=XFAc>fmRNpb<7?lTeXbq$ui!kea~?)t9G%urXR|FCb%E-tI0)IhjnT`dSe--XTUEiV$5Q~PGa z7|LkLwh!*^Qbm6@@;(p%ERp68^k=wot3TdS-JEoL@~29vNXj8A2J-@@RHRs&p0kz| z{a$D4DLLi4ds7ksl5$zuB$7*FLl65@SJz0$C8N>~brB>H%dY5z%j0)!HDfHE<5Ejl#G|A>+2yY5eXf!1+Ze)wAyniZjbq zOA1kEuC_HTtwaE`e%jAduBfO{I;wLJ*Tbb2kzS8um;mD1g`=-B(H~sgXwUa!o@9_X zJ1-dTo9xaYqV-~4+Ca{Z_vZnIHQnrrp^T^OINKaq6wVFme}KeO%_4%~*#u*U=wgo# z!f2hwH4Df0l(Or-Wb*27PV#`u2CEam+neiX>3IjW=y_Da`%mh4>HPX)SdPUed70$~ zE@JV7keXU~VksDKJtTZc(+T2ArATu%XxB5pTV6f$9s_JD>zATS;N5F|_f}k^U{_r< zuk9(4Li9&;Vf7Y1B~i>s=6@*FLjo-ZSW$I(^+nx(M#X@K zi4GnRlgA{uVZX`@6w82Vbw3q@``Rd`tzzoa?T16$Sq|G&+C$Uti5H~|i9mDB=fcW3X7tJr_vLow^zvfX5_ z<`2IH5pd$!(zzPyprCy zjS7!uU^9$cLAkU#*^M7qUPZ0D6$ERes!U$ZTpjmm-CSefnhZsYk~iH1Q{yeqMc(G5 zrq7sJhJd~JeEqBk4MoP=Qf5N1$!jY&7}5@j#5`CaA-s+)hgtA(Nf_p3EcuL((HHw z(`|hizUowy(}h7@fl4wm8k46R@3wD9B4y83^rf772Nc4{O84M7@G@i9*G?%m0jLWS zPR@$S9!S?U02Z-H*ul-_%CUJB02H0QJ=|7mIXklr86P`wsuBXg*~c8uo>U@iNGGMr z1r^pqBJ*%>PBvq|DH*kvpYnC}@yDS&fy?=T-nXAl9|STY86M z@#z|wG_xLpf!hFZn!56@Q8r_JfB1?3aY-g>MBSXu6C>qnIh-@n0Ms$Cg}fRL?()IEr9yux7N+f>|XrLQzND}l4N=h>0n&cLuEWXAUEC+wPqw?H?RaB zq49c*T-u?GQSiDsc8{CSaK7-?C5tg%quhKp&D=(Cm^p64!;v4c#GrJzCc355Y)&(v z6m_`*2y+-OF<9d-se8575OOPW!jHYXFC%Xc2Bw@gl5VS@ul^KiE`byTrm^u2x8nCF zVDh6A9jkC!p(ZouaX^O3_Yf8|AnxrDeQnlvO4i!cluun+d0K|p_;cd#TV_|+C?H9lXS#O+4#~r7Cfhw#s5_OTUT*lfp`$JU{ zs@D*8dlCR?UlSXo2_rgbZFsK=MjB!hvs)MqiUaZM=b|EPk@`ku<0G`|OKPa_SKOUh z%ca$lG@*d>cS~Jrd0IF@5znQX>YE#gAO`vfPhW?|R!UKF8suK&XDRPvix+l}eo{I$ATFGY((`881_7 z|9ZBU$UYk@*3X@@QgGvm%TqD~2qpjthbr2H+_nd)WGR>{KyfE6vL0mp zio5rtJs+p`r3tJ4FHHgxSz*4xH zryB9~IY{uOG(P;y{$ALV-jexEpiBfU4b8oe=%5SaIDf2;pg_i6Q~?FKT*dWS)#`_{ zU6I88)Q(v1s-NClyx561@$i@5x4?6?@>}a4aF1UL-RhOyigD8iwRJ@uO_qzJ>bLI@ z*^Bw5d!L0LFQoPm=m4wq(+_8@CqKC(O3i!QD|j4LMD;589M_S7 zU+*ycT%#JhJxB_#9L3>X&Q@L?MjS(g#bhk{9XJs0gaB)8is|seWLH?1$EkIiI#<2g z1>_rX@@51_Q*%Q5*HAyKsiLBApFHPH16fNvX2^VKm72C7C_Xa3SIk}q)1dJS2n?O; zz$u0O-e*t|QbedPwEFS7J(kiZ5Hf(zIv{;_rZ&d!J@!5hQMW>>WO+GLL7@G`7uW*s zrxb!x3rEfb7w#uy6x-VchSgYI%J9X2wjkH70m|!ByIWN164?8ur&7Bzm6IDja55;t zm7dvs((0Q>N>{nBDf#)?syEqM@B+AF*$FXHcC@i(RPNrz)+js;nl@Ie0XPP}% zocC#?d*3g&K68bBuvPOFjbDcbH(=0(ktjd2QxhR~S?L7|1XiaHB9c3p=DSVF2@Vnd zcobNW*1W(+`&Wk<`R^-)%@~vg2O=o{-kZSSknr*SE~5Z$({(YqB-T(+p*=zUL_n|do;|ZacfxM+^=Je3 z4{Z{X%j5OV^rovSy@%PPfA%x84^5EB=SWQ><_VmQqCa_dl8JX$>uLOlKp+cNAvg@kW?ueK!oTRI5 z23`smTHIajtUDr6TOP@i@zkxg7B7gUE3cGmkTg|*ILulr7T|XPM9FNqoF@O{PJ>5Y zZ=cGwWlm{qQ0ezGujcemN_i`r)kXGzH>lQC{Jr_ddU%lf!%N&o=plyCFKw&VFN+oU7s zwu}7ro*N2&e!}3U7R=3pk7E%|!m*TEwm!N*i55jAn*Q?U0S2DS#-W97jdf=TOhld|SUoYO5@}gh3;@ z*YV?dm7?X`14pSaV-V4(;Km9hmVM zJRRnjEVMUkYw7@Sl<=x+P_Hdz&ykNGbed{M+)FCcUsmob2qd#fpf3d*|&O zZ8@S*Z0{VmiQ5;KWH{xi5BIZNK#f?{wM>=d7h$)@0UtC9GzibwI$P#n@f2r3oyJsr zV=ZSN&4%kt(iiRh^ZhGMwQmopo@D~2V~%mImRZ8KF0=YF6DSHjyHCrhWw$5XHjdfA za?7+^`(YJ$aCi({tx9Q-5~JKdwm?gXpCd=uHNt&ReB7g+H!?jt^ZLMka`szb?&C>o z%)ek9y^-Y;P(@lChnV!I3cy7G7`cD2WWS>Qv;4uELQS)^S^sU34_`Zb1aC>$3~5mt z>X6HFJi5jvCSxoo`)n;Ow38umUmbCVoz zlYCL5lg}+IYiD{lk`Cc1pi+hl$a5;Q%Mr1c1_0QrQCI{G5N#@mvi$Y+?-9e(+PW6K zYW+5fCpPWLw^2KD3v)QB`~eH5^;^$vl?@ZNo0Fd0T}pLJJ3AJj+=Q7xdZvERvd@;S zOn(WF_c|?-(K;fOcpM`H`+kHsSn18(3`5c3Y+mNT9D&WDX!ZBGV<#({e&gHqIFLC7 z3l1;huC^Wh_AwHtM3-l2inNN~^X9&C`sahAUd_uL;F;e*8DbE#8ukKk5>SuAk1-co zJLE6jx3_nG`tCKWQa&;JS^x8?-!fygWX4l+ayyMDuoIq_pH6NaKzMc+NJ4i;wKLrf zE?_ZF+Br|E&^Ap^7 z@K!iI7fgXR;^t)Q9#b?d^YXWx0V&y0StCb@g)Sc6*~@q~&Dhsdo>@cI)}!A_Atf3I zi)ad|2M_uJbP_tNA0ls*PQQFp+98W)1l_vp+PQi62YToUPM`L5kbkDc54$7jLg(|) zXmhKrxDKsMeNvz$SUiObJwdrW1Q8y;$49IdD(6qh3*xJ*t_k;NYABgLj;dQlC(BC+1 zx`sVE$sI$N&iFc@^hH%U6W~cmcs<2$6(v{0Mfa^xl&^G~#5$#V{1TX_sFO-wFw>_< z-<(t>5%x`(z6`oeiEyuR6;OW&&d+byTlf~ho=6X*qi(F8rMk;gi&KYgwR&1C!& zcetv3uU<#Ng{9W0nymlk)4UR;wB-ou2U+yyEI^QrX@Tj>b%IT#A|e_v^jjvass{rkpF1xT3{)|~7iZ|pS8j(>&%p_xjF ziv_3wa8_4C*_%kBb)-*H6Y9AvJz(u8T!yu(fj(d<5CLsQp+@OpT` zA3F8lWh01pWH;o5^uVrr*^y zYdlGBnko$Fin*c$BK?L-t(Ky?K67SI{Pf07t+6-zvu6i1;Y^z=@A@o}d4oKo>5W*q zUhJf{XKKZE-}*C-ufG<|`74jl`a3&&EJpq!zC0uQK9hS7(0PI0*d#~m&Ws5xn#QNc zPA8H_l_~$Zx9^Ckh*Q|5T@4|gDZ@m}YySm#nDrr^WXgN7^gUa@GL1VGFT)alr*gXe z>Z0%AM%1}3F&lQsn>d)ojbw(HLr`8XoDe6EoNBQAY_7g~$OGI6FAfeY?|fW;C~ePn zMbX4W<^<{cxJ9}Cd=S(k7}#J=&N9rXr;HvzQ*Q@i2N2yO3eLH8%^7&)V>h;ys6*}o z#I)7WG)#c<6Ii&~vVylSmAO4UNDplP^~-nb09?yE!N0)Ve^IcZcUIhd{~sKgf^;0X^ZD*9V`#ErQu2nXR8%0 z_q~VE{R@p10>jY-&%gQZFR4}5+|a-qzk5w>$^UEGUnS-u29^HZm;J;C{u^%|1Ndxa zAe;a9=a+44xw*lH1iUi;`z1~ArI)R3lhqCcL#nD5R_Xs^j)?mn6|n!$%;l7QFYJH5 zmP{ga^T+POSpD0_|23z}4{x3e3D(i(=2W*R_i4|M=QBYgQ`E}dp#klU#Q^F{dwVC@ z^kj;A!0`7Ka^TJCSz4e*INUm!mov*tkog(AHEEK4<9t8u9G z0cc>CQD4HPwdFkg&JS*r5ncsDTU{L;�-LDp7{$lAKmaAT_H@Reg85DV1gME@u66 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 Vs=v2). Read the file COPYING that comes with GRASS for details. @author Martin Landa -@author Python parameterization Ondrej Pesek +@PyWPS, Python parameterization Ondrej Pesek """ import os @@ -43,6 +44,7 @@ import xml.sax.saxutils as saxutils import wx +from abc import ABC, abstractmethod from wx.lib import ogl from core import globalvar @@ -2546,7 +2548,522 @@ def _comment(self, comment): ) -class WritePythonFile: +class WriteScriptFile(ABC): + """Abstract class for scripts based on the model.""" + + @abstractmethod + def __init__(self, fd, model): + """Constructor to be overriden.""" + self.fd = None + self.model = None + self.indent = None + + # call method_write...() + + def _writeItem(self, item, ignoreBlock=True, variables={}): + """Write model object to Python file""" + if isinstance(item, ModelAction): + if ignoreBlock and item.GetBlockId(): + # ignore items in loops of conditions + return + self._writePythonAction( + item, variables, self.model.GetIntermediateData()[:3] + ) + elif isinstance(item, ModelLoop) or isinstance(item, ModelCondition): + # substitute condition + cond = item.GetLabel() + for variable in self.model.GetVariables(): + pattern = re.compile("%" + variable) + if pattern.search(cond): + value = variables[variable].get("value", "") + if variables[variable].get("type", "string") == "string": + value = '"' + value + '"' + cond = pattern.sub(value, cond) + if isinstance(item, ModelLoop): + condVar, condText = map( + lambda x: x.strip(), re.split("\s* in \s*", cond) + ) + cond = "%sfor %s in " % (" " * self.indent, condVar) + if condText[0] == "`" and condText[-1] == "`": + task = GUI(show=None).ParseCommand(cmd=utils.split(condText[1:-1])) + cond += "grass.read_command(" + cond += ( + self._getPythonActionCmd(task, len(cond), variables=[condVar]) + + ".splitlines()" + ) + else: + cond += condText + self.fd.write("%s:\n" % cond) + self.indent += 4 + variablesLoop = variables.copy() + variablesLoop[condVar] = None + for action in item.GetItems(self.model.GetItems(objType=ModelAction)): + self._writeItem(action, ignoreBlock=False, variables=variablesLoop) + self.indent -= 4 + if isinstance(item, ModelCondition): + self.fd.write("%sif %s:\n" % (" " * self.indent, cond)) + self.indent += 4 + condItems = item.GetItems() + for action in condItems["if"]: + self._writeItem(action, ignoreBlock=False) + if condItems["else"]: + self.indent -= 4 + self.fd.write("%selse:\n" % (" " * self.indent)) + self.indent += 4 + for action in condItems["else"]: + self._writeItem(action, ignoreBlock=False) + self.indent += 4 + self.fd.write("\n") + if isinstance(item, ModelComment): + self._writePythonComment(item) + + def _writePythonComment(self, item): + """Write model comment to Python file""" + for line in item.GetLabel().splitlines(): + self.fd.write("#" + line + "\n") + + @staticmethod + def _getParamName(parameter_name, item): + return "{module_name}{module_id}_{param_name}".format( + module_name=re.sub("[^a-zA-Z]+", "", item.GetLabel()), + module_id=item.GetId(), + param_name=parameter_name, + ) + + def _getItemFlags(self, item, opts, variables): + """Get item flags that are needed to be parsed in the script. + + :param item: module + :param opts: options of the task + :param variables: variables of the item + :return: string with flag names set to True, string with + comma-separated flags that are parameterized, list of + parameterized boolean parameters like verbose or overwrite (needed + as they are also tagged as flags) + """ + item_params = [] + item_true_flags = "" + item_parameterized_flags = [] + + parameterized_flags = [v["name"] for v in variables["flags"]] + + for f in opts["flags"]: + if f.get("name") in parameterized_flags and len(f.get("name")) == 1: + item_parameterized_flags.append( + '"{}"'.format(self._getParamName(f.get("name"), item)) + ) + if f.get("value", False): + name = f.get("name", "") + if len(name) > 1: + item_params.append("%s=True" % name) + else: + item_true_flags += name + + item_parameterized_flags = ", ".join(item_parameterized_flags) + + return item_true_flags, item_parameterized_flags, item_params + + +class WritePyWPSFile(WriteScriptFile): + """Class for exporting model to PyWPS script.""" + + def __init__(self, fd, model): + """Class for exporting model to PyWPS script.""" + self.fd = fd + self.model = model + self.indent = 8 + + self._writePyWPS() + + def _writePyWPS(self): + """Write PyWPS model to file""" + properties = self.model.GetProperties() + + self.fd.write( + r"""#!/usr/bin/env python3 + +import sys +import os +import atexit +import tempfile +from grass.script import run_command +from pywps import Process, LiteralInput, ComplexInput, ComplexOutput, Format + + +class Model(Process): + + def __init__(self): + inputs = list() + outputs = list() + +""" + ) + + for item in self.model.GetItems(): + self._write_input_outputs(item, self.model.GetIntermediateData()[:3]) + + self.fd.write( + r""" super(Model, self).__init__( + self._handler, + identifier="{identifier}", + title="{title}", + inputs=inputs, + outputs=outputs, + # here you could also specify the GRASS location, for example: + # grass_location="EPSG:5514", + abstract="{abstract}", + version="1.0", + store_supported=True, + status_supported=True) +""".format( + identifier=properties["name"], + title=properties["name"], + abstract='""'.join(properties["description"].splitlines()), + ) + ) + + self.fd.write( + """ + @staticmethod + def _handler(request, response):""" + ) + + self._writeHandler() + + for item in self.model.GetItems(): + if item.GetParameterizedParams()["flags"]: + self.fd.write( + r""" + +def getParameterizedFlags(paramFlags, itemFlags): + fl = "" + for i in [key for key, value in paramFlags.items() if value[0].data == "True"]: + if i in itemFlags: + fl += i[-1] + + return fl +""" + ) + break + + self.fd.write( + """ + +if __name__ == "__main__": + from pywps.app.Service import Service + + processes = [Model()] + application = Service(processes) +""" + ) + + def _write_input_outputs(self, item, intermediates): + parameterized_params = item.GetParameterizedParams() + + for flag in parameterized_params["flags"]: + if flag["label"]: + desc = flag["label"] + else: + desc = flag["description"] + + if flag["value"]: + value = '\n{}default="{}"'.format( + " " * (self.indent + 4), flag["value"] + ) + else: + value = '\n{}default="False"'.format(" " * (self.indent + 4)) + + io_data = "inputs" + object_type = "LiteralInput" + format_spec = 'data_type="string",' + + self._write_input_output_object( + io_data, + object_type, + flag["name"], + item, + desc, + format_spec, + value, + ) + + self.fd.write("\n") + + for param in parameterized_params["params"]: + desc = self._getParamDesc(param) + value = self._getParamValue(param) + + if "input" in param["name"]: + io_data = "inputs" + object_type = "ComplexInput" + format_spec = self._getSupportedFormats(param["prompt"]) + else: + io_data = "inputs" + object_type = "LiteralInput" + format_spec = 'data_type="{}"'.format(param["type"]) + + self._write_input_output_object( + io_data, + object_type, + param["name"], + item, + desc, + format_spec, + value, + ) + + self.fd.write("\n") + + # write ComplexOutputs + for param in item.GetParams()["params"]: + desc = self._getParamDesc(param) + value = param["value"] + age = param["age"] + + # ComplexOutput if: outputing a new non-intermediate layer and + # either not empty or parameterized + if ( + age == "new" + and not any(value in i for i in intermediates) + and (value != "" or param in item.GetParameterizedParams()["params"]) + ): + io_data = "outputs" + object_type = "ComplexOutput" + format_spec = self._getSupportedFormats(param["prompt"]) + + self._write_input_output_object( + io_data, object_type, param["name"], item, desc, format_spec, "" + ) + + self.fd.write("\n") + + def _write_input_output_object( + self, + io_data, + object_type, + name, + item, + desc, + format_spec, + value, + ): + self.fd.write( + """ {ins_or_outs}.append({lit_or_complex}( + identifier="{param_name}", + title="{description}", + {special_params}{value})) +""".format( + ins_or_outs=io_data, + lit_or_complex=object_type, + param_name=self._getParamName(name, item), + description=desc, + special_params=format_spec, + value=value, + ) + ) + + def _writeHandler(self): + for item in self.model.GetItems(): + self._writeItem(item, variables=item.GetParameterizedParams()) + + self.fd.write("\n{}return response\n".format(" " * self.indent)) + + def _writePythonAction(self, item, variables={}, intermediates=None): + """Write model action to Python file""" + task = GUI(show=None).ParseCommand(cmd=item.GetLog(string=False)) + strcmd = "\n%srun_command(" % (" " * self.indent) + self.fd.write( + strcmd + self._getPythonActionCmd(item, task, len(strcmd) - 1, variables) + ) + + # write v.out.ogr and r.out.gdal exports for all outputs + for param in item.GetParams()["params"]: + value = param["value"] + age = param["age"] + + # output if: outputing a new non-intermediate layer and + # either not empty or parameterized + if ( + age == "new" + and not any(value in i for i in intermediates) + and (value != "" or param in item.GetParameterizedParams()["params"]) + ): + if param["prompt"] == "vector": + command = "v.out.ogr" + format = '"GML"' + extension = ".gml" + elif param["prompt"] == "raster": + command = "r.out.gdal" + format = '"GTiff"' + extension = ".tif" + else: + # TODO: Support 3D + command = "WRITE YOUR EXPORT COMMAND" + format = '"WRITE YOUR EXPORT FORMAT"' + extension = "WRITE YOUR EXPORT EXTENSION" + + n = param.get("name", None) + param_name = self._getParamName(n, item) + + keys = param.keys() + if "parameterized" in keys and param["parameterized"] is True: + param_request = 'request.inputs["{}"][0].data'.format(param_name) + else: + param_request = '"{}"'.format(param["value"]) + + # if True, write the overwrite parameter to the model command + overwrite = self.model.GetProperties().get("overwrite", False) + if overwrite is True: + overwrite_string = ",\n{}overwrite=True".format( + " " * (self.indent + 12) + ) + else: + overwrite_string = "" + + self.fd.write( + """ +{run_command}"{cmd}", +{indent1}input={input}, +{indent2}output=os.path.join( +{indent3}tempfile.gettempdir(), +{indent4}{out} + "{format_ext}"), +{indent5}format={format}{overwrite_string}) +""".format( + run_command=strcmd, + cmd=command, + indent1=" " * (self.indent + 12), + input=param_request, + indent2=" " * (self.indent + 12), + indent3=" " * (self.indent + 16), + indent4=" " * (self.indent + 16), + out=param_request, + format_ext=extension, + indent5=" " * (self.indent + 12), + format=format, + overwrite_string=overwrite_string, + ) + ) + + left_side_out = 'response.outputs["{}"].file'.format(param_name) + right_side_out = ( + "os.path.join(\n{indent1}" + 'tempfile.gettempdir(),\n{indent2}{out} + "' + '{format_ext}")'.format( + indent1=" " * (self.indent + 4), + indent2=" " * (self.indent + 4), + out=param_request, + format_ext=extension, + ) + ) + self.fd.write( + "\n{}{} = {}".format( + " " * self.indent, left_side_out, right_side_out + ) + ) + + def _getPythonActionCmd(self, item, task, cmdIndent, variables={}): + opts = task.get_options() + + ret = "" + parameterizedParams = [v["name"] for v in variables["params"]] + + flags, itemParameterizedFlags, params = self._getItemFlags( + item, opts, variables + ) + + out = None + + for p in opts["params"]: + name = p.get("name", None) + value = p.get("value", None) + + if (name and value) or (name in parameterizedParams): + ptype = p.get("type", "string") + foundVar = False + + if name in parameterizedParams: + foundVar = True + if "input" in name: + value = 'request.inputs["{}"][0].file'.format( + self._getParamName(name, item) + ) + else: + value = 'request.inputs["{}"][0].data'.format( + self._getParamName(name, item) + ) + + if foundVar or ptype != "string": + params.append("{}={}".format(name, value)) + else: + params.append('{}="{}"'.format(name, value)) + + ret += '"%s"' % task.get_name() + if flags: + ret += ',\n{indent}flags="{fl}"'.format(indent=" " * cmdIndent, fl=flags) + if itemParameterizedFlags: + ret += " + getParameterizedFlags(\n{}request.inputs, [{}])".format( + " " * (cmdIndent + 4), itemParameterizedFlags + ) + elif itemParameterizedFlags: + ret += ",\n{}flags=getParameterizedFlags(request.inputs, [{}])".format( + " " * cmdIndent, itemParameterizedFlags + ) + + if len(params) > 0: + ret += ",\n" + for opt in params[:-1]: + ret += "%s%s,\n" % (" " * cmdIndent, opt) + ret += "%s%s)" % (" " * cmdIndent, params[-1]) + else: + ret += ")\n" + + # TODO: Write the next line only for those not-tagged as intermediate + if out: + ret += '\n\n{}response.outputs["{}"].file = "{}"'.format( + " " * self.indent, out, out + ) + + return ret + + def _getParamDesc(self, param): + if param["label"]: + desc = param["label"] + else: + desc = param["description"] + + return desc + + def _getParamValue(self, param): + if param["value"] and "output" not in param["name"]: + if param["type"] in ["float", "integer"]: + value = param["value"] + else: + value = '"{}"'.format(param["value"]) + + value = ",\n{}default={}".format(" " * (self.indent + 4), value) + else: + value = "" + + return value + + @staticmethod + def _getSupportedFormats(prompt): + """Get supported formats of an item. + + :param prompt: param['prompt'] of an item + :return: + """ + if prompt == "vector": + sup_formats = 'Format("application/gml+xml")' + elif prompt == "raster": + sup_formats = 'Format("image/tif")' + else: + sup_formats = "FORMAT UNKNOWN - WRITE YOUR OWN" + + return "supported_formats=[{}]".format(sup_formats) + + +class WritePythonFile(WriteScriptFile): def __init__(self, fd, model): """Class for exporting model to Python script @@ -2687,31 +3204,31 @@ def cleanup(): ) if rast: self.fd.write( - r""" run_command('g.remove', flags='f', type='raster', - name=%s) + r""" run_command("g.remove", flags="f", type="raster", + name=%s) """ - % ",".join(map(lambda x: "'" + x + "'", rast)) + % ",".join(map(lambda x: '"' + x + '"', rast)) ) if vect: self.fd.write( - r""" run_command('g.remove', flags='f', type='vector', - name=%s) + r""" run_command("g.remove", flags="f", type="vector", + name=%s) """ - % ",".join(map(lambda x: "'" + x + "'", vect)) + % ",".join(map(lambda x: '"' + x + '"', vect)) ) if rast3d: self.fd.write( - r""" run_command('g.remove', flags='f', type='raster_3d', - name=%s) + r""" run_command("g.remove", flags="f", type="raster_3d", + name=%s) """ - % ",".join(map(lambda x: "'" + x + "'", rast3d)) + % ",".join(map(lambda x: '"' + x + '"', rast3d)) ) if not rast and not vect and not rast3d: self.fd.write(" pass\n") self.fd.write("\ndef main(options, flags):\n") for item in self.model.GetItems(): - self._writePythonItem(item, variables=item.GetParameterizedParams()) + self._writeItem(item, variables=item.GetParameterizedParams()) self.fd.write(" return 0\n") @@ -2720,12 +3237,8 @@ def cleanup(): self.fd.write( r""" def getParameterizedFlags(paramFlags, itemFlags): - fl = '' -""" - ) - - self.fd.write( - """ for i in [key for key, value in paramFlags.items() if value == 'True']: + fl = "" + for i in [key for key, value in paramFlags.items() if value == "True"]: if i in itemFlags: fl += i[-1] @@ -2747,64 +3260,7 @@ def getParameterizedFlags(paramFlags, itemFlags): self.fd.write(" sys.exit(main(options, flags))\n") - def _writePythonItem(self, item, ignoreBlock=True, variables={}): - """Write model object to Python file""" - if isinstance(item, ModelAction): - if ignoreBlock and item.GetBlockId(): - # ignore items in loops of conditions - return - self._writePythonAction(item, variables=variables) - elif isinstance(item, ModelLoop) or isinstance(item, ModelCondition): - # substitute condition - cond = item.GetLabel() - for variable in self.model.GetVariables(): - pattern = re.compile("%" + variable) - if pattern.search(cond): - value = variables[variable].get("value", "") - if variables[variable].get("type", "string") == "string": - value = '"' + value + '"' - cond = pattern.sub(value, cond) - if isinstance(item, ModelLoop): - condVar, condText = map( - lambda x: x.strip(), re.split("\s* in \s*", cond) - ) - cond = "%sfor %s in " % (" " * self.indent, condVar) - if condText[0] == "`" and condText[-1] == "`": - task = GUI(show=None).ParseCommand(cmd=utils.split(condText[1:-1])) - cond += "grass.read_command(" - cond += ( - self._getPythonActionCmd(task, len(cond), variables=[condVar]) - + ".splitlines()" - ) - else: - cond += condText - self.fd.write("%s:\n" % cond) - self.indent += 4 - variablesLoop = variables.copy() - variablesLoop[condVar] = None - for action in item.GetItems(self.model.GetItems(objType=ModelAction)): - self._writePythonItem( - action, ignoreBlock=False, variables=variablesLoop - ) - self.indent -= 4 - if isinstance(item, ModelCondition): - self.fd.write("%sif %s:\n" % (" " * self.indent, cond)) - self.indent += 4 - condItems = item.GetItems() - for action in condItems["if"]: - self._writePythonItem(action, ignoreBlock=False) - if condItems["else"]: - self.indent -= 4 - self.fd.write("%selse:\n" % (" " * self.indent)) - self.indent += 4 - for action in condItems["else"]: - self._writePythonItem(action, ignoreBlock=False) - self.indent += 4 - self.fd.write("\n") - if isinstance(item, ModelComment): - self._writePythonComment(item) - - def _writePythonAction(self, item, variables={}): + def _writePythonAction(self, item, variables={}, intermediates=None): """Write model action to Python file""" task = GUI(show=None).ParseCommand(cmd=item.GetLog(string=False)) strcmd = "%srun_command(" % (" " * self.indent) @@ -2816,25 +3272,11 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}): opts = task.get_options() ret = "" - flags = "" - params = list() - itemParameterizedFlags = list() parameterizedParams = [v["name"] for v in variables["params"]] - parameterizedFlags = [v["name"] for v in variables["flags"]] - for f in opts["flags"]: - if f.get("name") in parameterizedFlags and len(f.get("name")) == 1: - itemParameterizedFlags.append( - '"{}"'.format(self._getParamName(f.get("name"), item)) - ) - if f.get("value", False): - name = f.get("name", "") - if len(name) > 1: - params.append("%s = True" % name) - else: - flags += name - - itemParameterizedFlags = ", ".join(itemParameterizedFlags) + flags, itemParameterizedFlags, params = self._getItemFlags( + item, opts, variables + ) for p in opts["params"]: name = p.get("name", None) @@ -2875,11 +3317,6 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}): return ret - def _writePythonComment(self, item): - """Write model comment to Python file""" - for line in item.GetLabel().splitlines(): - self.fd.write("#" + line + "\n") - def _substituteVariable(self, string, variable, data): """Substitute variable in the string @@ -2914,13 +3351,6 @@ def _substituteVariable(self, string, variable, data): return result.strip("+") - def _getParamName(self, parameter_name, item): - return "{module_name}{module_id}_{param_name}".format( - module_name=re.sub("[^a-zA-Z]+", "", item.GetLabel()), - module_id=item.GetId(), - param_name=parameter_name, - ) - class ModelParamDialog(wx.Dialog): def __init__( diff --git a/gui/wxpython/gui_core/pystc.py b/gui/wxpython/gui_core/pystc.py index 4c377f333ed..03350071347 100644 --- a/gui/wxpython/gui_core/pystc.py +++ b/gui/wxpython/gui_core/pystc.py @@ -89,6 +89,9 @@ def __init__(self, parent, id=wx.ID_ANY, statusbar=None): self.parent = parent self.statusbar = statusbar + # for support of different export in gmodeler + self.script_type = "Python" + self.modified = False # content modified ? # this is supposed to get monospace @@ -260,7 +263,12 @@ def OnKeyPressed(self, event): self.modified = True if self.statusbar: self.statusbar.SetStatusText( - _("Python script contains local modifications"), 0 + _( + "{} script contains local modifications".format( + self.script_type + ) + ), + 0, ) event.Skip() From 28c75de42def60398d9c66df6df25f27ae380d4f Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Fri, 21 Oct 2022 09:58:05 +0200 Subject: [PATCH 047/123] docker ubuntu: update to Ubuntu 22.04 (#2602) - update to Ubuntu 22.04 base image - update to latest PDAL (to be compiled since laz-perf missing from Ubuntu) - update to latest laz-perf Sync Dockerfile in main directory to docker/Dockerfile (avoids current confusion) --- Dockerfile | 332 +++++++++++++++++++++++++-------------- docker/ubuntu/Dockerfile | 10 +- 2 files changed, 223 insertions(+), 119 deletions(-) diff --git a/Dockerfile b/Dockerfile index e72d1ab2bb9..65295bb123d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,86 +1,157 @@ -FROM ubuntu:18.04 +FROM ubuntu:22.04 -LABEL authors="Vaclav Petras,Markus Neteler" -LABEL maintainer="wenzeslaus@gmail.com,neteler@osgeo.org" +LABEL authors="Carmen Tawalika,Markus Neteler,Anika Weinmann" +LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis.de" -# system environment ENV DEBIAN_FRONTEND noninteractive -# data directory - not using the base images volume because then the permissions cannot be adapted -ENV DATA_DIR /data - -# GRASS GIS compile dependencies -RUN apt-get update \ - && apt-get install -y --no-install-recommends --no-install-suggests \ - build-essential \ - libblas-dev \ - libbz2-dev \ - libcairo2-dev \ - libfftw3-dev \ - libfreetype6-dev \ - libgdal-dev \ - libgeos-dev \ - libglu1-mesa-dev \ - libgsl0-dev \ - libjpeg-dev \ - liblapack-dev \ - libncurses5-dev \ - libnetcdf-dev \ - libopenjp2-7 \ - libopenjp2-7-dev \ - libpdal-dev pdal \ - libpdal-plugin-python \ - libpng-dev \ - libpq-dev \ - libproj-dev \ - libreadline-dev \ - libsqlite3-dev \ - libtiff-dev \ - libxmu-dev \ - libzstd-dev \ - bison \ - flex \ - g++ \ - gettext \ - gdal-bin \ - language-pack-en-base \ - libfftw3-bin \ - make \ - ncurses-bin \ - netcdf-bin \ - proj-bin \ - proj-data \ - python3 \ - python3-dateutil \ - python3-dev \ - python3-numpy \ - python3-pil \ - python3-pip \ - python3-ply \ - python3-six \ - python3-wxgtk4.0 \ - python3-gdal \ - python3-matplotlib \ - sqlite3 \ - subversion \ - unixodbc-dev \ - zlib1g-dev \ - && apt-get autoremove \ - && apt-get clean && \ - mkdir -p $DATA_DIR +# define versions to be used +# https://github.com/PDAL/PDAL/releases +ARG PDAL_VERSION=2.4.3 +# https://github.com/hobuinc/laz-perf/releases +ARG LAZ_PERF_VERSION=3.2.0 + +SHELL ["/bin/bash", "-c"] + +WORKDIR /tmp + +RUN apt-get update && apt-get upgrade -y && \ + apt-get install -y --no-install-recommends --no-install-suggests \ + build-essential \ + bison \ + bzip2 \ + cmake \ + curl \ + flex \ + g++ \ + gcc \ + gdal-bin \ + git \ + language-pack-en-base \ + libbz2-dev \ + libcairo2 \ + libcairo2-dev \ + libcurl4-gnutls-dev \ + libfftw3-bin \ + libfftw3-dev \ + libfreetype6-dev \ + libgdal-dev \ + libgeos-dev \ + libgsl0-dev \ + libjpeg-dev \ + libjsoncpp-dev \ + libnetcdf-dev \ + libncurses5-dev \ + libopenblas-base \ + libopenblas-dev \ + libopenjp2-7 \ + libopenjp2-7-dev \ + libpnglite-dev \ + libpq-dev \ + libproj-dev \ + libpython3-all-dev \ + libsqlite3-dev \ + libtiff-dev \ + libzstd-dev \ + locales \ + make \ + mesa-common-dev \ + moreutils \ + ncurses-bin \ + netcdf-bin \ + proj-bin \ + proj-data \ + python3 \ + python3-dateutil \ + python3-dev \ + python3-magic \ + python3-numpy \ + python3-pil \ + python3-pip \ + python3-ply \ + python3-setuptools \ + python3-venv \ + software-properties-common \ + sqlite3 \ + subversion \ + unzip \ + vim \ + wget \ + zip \ + zlib1g-dev RUN echo LANG="en_US.UTF-8" > /etc/default/locale -ENV LANG C.UTF-8 -ENV LC_ALL C.UTF-8 - -RUN mkdir /code -RUN mkdir /code/grass - -# add repository files to the image -COPY . /code/grass - -WORKDIR /code/grass - +RUN echo en_US.UTF-8 UTF-8 >> /etc/locale.gen && locale-gen + +## install laz-perf (missing from https://packages.ubuntu.com/) +RUN apt-get install cmake +WORKDIR /src +RUN wget -q https://github.com/hobu/laz-perf/archive/${LAZ_PERF_VERSION}.tar.gz -O laz-perf-${LAZ_PERF_VERSION}.tar.gz && \ + tar -zxf laz-perf-${LAZ_PERF_VERSION}.tar.gz && \ + cd laz-perf-${LAZ_PERF_VERSION} && \ + mkdir build && \ + cd build && \ + cmake .. && \ + make && \ + make install + +## fetch vertical datums for PDAL and store into PROJ dir +WORKDIR /src +RUN mkdir vdatum && \ + cd vdatum && \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2012.zip && unzip -j -u usa_geoid2012.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2009.zip && unzip -j -u usa_geoid2009.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2003.zip && unzip -j -u usa_geoid2003.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid1999.zip && unzip -j -u usa_geoid1999.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/vertcon/vertconc.gtx && mv vertconc.gtx /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/vertcon/vertcone.gtx && mv vertcone.gtx /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/vertcon/vertconw.gtx && mv vertconw.gtx /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/egm96_15/egm96_15.gtx && mv egm96_15.gtx /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/egm08_25/egm08_25.gtx && mv egm08_25.gtx /usr/share/proj; \ + cd .. && \ + rm -rf vdatum + +## install pdal +ENV NUMTHREADS=4 +WORKDIR /src +RUN wget -q \ + https://github.com/PDAL/PDAL/releases/download/${PDAL_VERSION}/PDAL-${PDAL_VERSION}-src.tar.gz && \ + tar xfz PDAL-${PDAL_VERSION}-src.tar.gz && \ + cd /src/PDAL-${PDAL_VERSION}-src && \ + mkdir build && \ + cd build && \ + cmake .. \ + -G "Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_C_COMPILER=gcc \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_MAKE_PROGRAM=make \ + -DBUILD_PLUGIN_PYTHON=ON \ + -DBUILD_PLUGIN_CPD=OFF \ + -DBUILD_PLUGIN_GREYHOUND=ON \ + -DBUILD_PLUGIN_HEXBIN=ON \ + -DHEXER_INCLUDE_DIR=/usr/include/ \ + -DBUILD_PLUGIN_NITF=OFF \ + -DBUILD_PLUGIN_ICEBRIDGE=ON \ + -DBUILD_PLUGIN_PGPOINTCLOUD=ON \ + -DBUILD_PGPOINTCLOUD_TESTS=OFF \ + -DBUILD_PLUGIN_SQLITE=ON \ + -DWITH_LASZIP=ON \ + -DWITH_LAZPERF=ON \ + -DWITH_TESTS=ON && \ + make -j $NUMTHREADS && \ + make install + +# copy grass gis source +WORKDIR /src +COPY . /src/grass_build/ +WORKDIR /src/grass_build + +# Cleanup potentially leftover GISRC file with wrong path to "demolocation" +RUN rm -f /src/grass_build/dist.*/demolocation/.grassrc* + +# Set environmental variables for GRASS GIS compilation, without debug symbols # Set gcc/g++ environmental variables for GRASS GIS compilation, without debug symbols ENV MYCFLAGS "-O2 -std=gnu99 -m64" ENV MYLDFLAGS "-s" @@ -90,51 +161,82 @@ ENV LDFLAGS "$MYLDFLAGS" ENV CFLAGS "$MYCFLAGS" ENV CXXFLAGS "$MYCXXFLAGS" -# Configure, compile and install GRASS GIS -ENV NUMTHREADS=2 -RUN ./configure \ - --enable-largefile \ - --with-cxx \ - --with-nls \ - --with-readline \ - --with-sqlite \ - --with-bzlib \ - --with-zstd \ - --with-cairo --with-cairo-ldflags=-lfontconfig \ - --with-freetype --with-freetype-includes="/usr/include/freetype2/" \ - --with-fftw \ - --with-netcdf \ - --with-pdal \ - --with-proj --with-proj-share=/usr/share/proj \ - --with-geos=/usr/bin/geos-config \ - --with-postgres --with-postgres-includes="/usr/include/postgresql" \ - --with-opengl-libs=/usr/include/GL \ - && make -j $NUMTHREADS && make install && ldconfig - -# enable simple grass command regardless of version number -RUN if [ ! -e /usr/local/bin/grass ] ; then ln -s /usr/local/bin/grass* /usr/local/bin/grass ; fi +# Configure compile and install GRASS GIS +ENV GRASS_PYTHON=/usr/bin/python3 +ENV NUMTHREADS=4 +RUN make distclean || echo "nothing to clean" +RUN /src/grass_build/configure \ + --with-cxx \ + --enable-largefile \ + --with-proj-share=/usr/share/proj \ + --with-gdal=/usr/bin/gdal-config \ + --with-geos \ + --with-sqlite \ + --with-cairo --with-cairo-ldflags=-lfontconfig \ + --with-freetype --with-freetype-includes="/usr/include/freetype2/" \ + --with-fftw \ + --with-postgres --with-postgres-includes="/usr/include/postgresql" \ + --with-netcdf \ + --with-zstd \ + --with-bzlib \ + --with-pdal \ + --without-mysql \ + --without-odbc \ + --without-openmp \ + --without-opengl \ + && make -j $NUMTHREADS \ + && make install && ldconfig + +# Unset environmental variables to avoid later compilation issues +ENV INTEL "" +ENV MYCFLAGS "" +ENV MYLDFLAGS "" +ENV MYCXXFLAGS "" +ENV LD_LIBRARY_PATH "" +ENV LDFLAGS "" +ENV CFLAGS "" +ENV CXXFLAGS "" + +# set SHELL var to avoid /bin/sh fallback in interactive GRASS GIS sessions +ENV SHELL /bin/bash +ENV LC_ALL "en_US.UTF-8" +ENV GRASS_SKIP_MAPSET_OWNER_CHECK 1 + +# Create generic GRASS GIS lib name regardless of version number +RUN ln -sf /usr/local/grass83 /usr/local/grass + +# show GRASS GIS, PROJ, GDAL etc versions +RUN grass --tmp-location EPSG:4326 --exec g.version -rge && \ + pdal --version && \ + python3 --version # Reduce the image size RUN apt-get autoremove -y RUN apt-get clean -y +RUN rm -r /src/grass_build/.git -# set SHELL var to avoid /bin/sh fallback in interactive GRASS GIS sessions in docker -ENV SHELL /bin/bash - -# Fix permissions -RUN chmod -R a+rwx $DATA_DIR +WORKDIR /scripts -# create a user -RUN useradd -m -U grass +# install external GRASS GIS session Python API +RUN pip3 install grass-session -# declare data volume late so permissions apply -VOLUME $DATA_DIR -WORKDIR $DATA_DIR +# install GRASS GIS extensions +RUN grass --tmp-location EPSG:4326 --exec g.extension extension=r.in.pdal -# Further reduce the docker image size -RUN rm -rf /code/grass +# add GRASS GIS envs for python usage +ENV GISBASE "/usr/local/grass/" +ENV GRASSBIN "/usr/local/bin/grass" +ENV PYTHONPATH "${PYTHONPATH}:$GISBASE/etc/python/" +ENV LD_LIBRARY_PATH "$LD_LIBRARY_PATH:$GISBASE/lib" -# switch the user -USER grass +WORKDIR /tmp +COPY docker/testdata/simple.laz . +WORKDIR /scripts +COPY docker/testdata/test_grass_session.py . +## just scan the LAZ file +# Not yet ready for GRASS GIS 8: +#RUN /usr/bin/python3 /scripts/test_grass_session.py +RUN grass --tmp-location EPSG:25832 --exec r.in.pdal input="/tmp/simple.laz" output="count_1" method="n" resolution=1 -s -CMD ["/usr/local/bin/grass", "--version"] +WORKDIR /grassdb +VOLUME /grassdb diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index b9f9ad0c76d..65295bb123d 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:22.04 LABEL authors="Carmen Tawalika,Markus Neteler,Anika Weinmann" LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis.de" @@ -6,8 +6,10 @@ LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis. ENV DEBIAN_FRONTEND noninteractive # define versions to be used -ARG PDAL_VERSION=2.2.0 -ARG LAZ_PERF_VERSION=1.5.0 +# https://github.com/PDAL/PDAL/releases +ARG PDAL_VERSION=2.4.3 +# https://github.com/hobuinc/laz-perf/releases +ARG LAZ_PERF_VERSION=3.2.0 SHELL ["/bin/bash", "-c"] @@ -81,7 +83,7 @@ RUN apt-get update && apt-get upgrade -y && \ RUN echo LANG="en_US.UTF-8" > /etc/default/locale RUN echo en_US.UTF-8 UTF-8 >> /etc/locale.gen && locale-gen -## install laz-perf +## install laz-perf (missing from https://packages.ubuntu.com/) RUN apt-get install cmake WORKDIR /src RUN wget -q https://github.com/hobu/laz-perf/archive/${LAZ_PERF_VERSION}.tar.gz -O laz-perf-${LAZ_PERF_VERSION}.tar.gz && \ From d6e78491fba5d573917e8f304188ed698e752ed8 Mon Sep 17 00:00:00 2001 From: dnewcomb Date: Sat, 22 Oct 2022 17:16:54 -0400 Subject: [PATCH 048/123] nsis installer changed SID of grass82.py (#2605) --- mswindows/GRASS-Installer.nsi.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mswindows/GRASS-Installer.nsi.tmpl b/mswindows/GRASS-Installer.nsi.tmpl index 46ff7c9a127..fc1155ce94d 100644 --- a/mswindows/GRASS-Installer.nsi.tmpl +++ b/mswindows/GRASS-Installer.nsi.tmpl @@ -758,8 +758,8 @@ Section "GRASS" SecGRASS Push 'config_projshare = "$INSTDIR\share\proj"' ; string to replace whole line with Call ReplaceLineStr - ;replace BU with numeric group name for local users - AccessControl::SetOnFile "$INSTDIR\etc\grass@GRASS_VERSION_MAJOR@@GRASS_VERSION_MINOR@.py" "(S-1-5-32-545)" "GenericRead + GenericExecute" + ;replace BU with numeric group name for local users. Users S-1-5-32-545 does not work for Windows Enterprise. Try Authenticated Users S-1-5-11 + AccessControl::SetOnFile "$INSTDIR\etc\grass@GRASS_VERSION_MAJOR@@GRASS_VERSION_MINOR@.py" "(S-1-5-11)" "GenericRead + GenericExecute" SectionEnd ;-------------------------------------------------------------------------- From 68e34f70a944b5cf6946ad56ebdf7b436e8924f5 Mon Sep 17 00:00:00 2001 From: Tomas Zigo <50632337+tmszi@users.noreply.github.com> Date: Sun, 23 Oct 2022 13:03:13 +0200 Subject: [PATCH 049/123] utils: module HTML man page use hamburger menu TOC for screen width < 1024 px (#2606) * utils: module HTML man page use hamburger menu TOC for screen width < 1024 px * Fix flake8, black errors. * g.extension: copy CSS style file into addons docs HTML dir for every addon instalation * g.extension: copy hamburger menu SVG image files into addons docs HTML dir for every addon instalation * utils: set CSS class for every hamburger menu link list item To prevent the link path from being replaced with a local path during addon installation. Example: `DESCRIPTION` with `DESCRIPTION` * utils: fix space between HTML element attributes * man: install module HTML man page hamburger menu TOC SVG images --- man/Makefile | 8 +++ man/grassdocs.css | 91 +++++++++++++++++++++++++++++- man/hamburger_menu.svg | 75 ++++++++++++++++++++++++ man/hamburger_menu_close.svg | 69 ++++++++++++++++++++++ scripts/g.extension/g.extension.py | 5 +- utils/mkhtml.py | 84 ++++++++++++++++++++++----- 6 files changed, 313 insertions(+), 19 deletions(-) create mode 100644 man/hamburger_menu.svg create mode 100644 man/hamburger_menu_close.svg diff --git a/man/Makefile b/man/Makefile index 8c48c0ac0eb..1a189c8d7c8 100644 --- a/man/Makefile +++ b/man/Makefile @@ -7,6 +7,8 @@ MANPAGES := $(patsubst $(HTMLDIR)/%.html,$(MANDIR)/%.$(MANSECT),$(wildcard $(HTM DSTFILES := \ $(HTMLDIR)/grassdocs.css \ $(HTMLDIR)/grass_logo.png \ + $(HTMLDIR)/hamburger_menu.svg \ + $(HTMLDIR)/hamburger_menu_close.svg \ $(HTMLDIR)/grass_icon.png \ $(HTMLDIR)/jquery.fixedheadertable.min.js \ $(HTMLDIR)/parser_standard_options.css \ @@ -148,6 +150,12 @@ $(HTMLDIR)/grassdocs.css: grassdocs.css $(HTMLDIR)/grass_logo.png: grass_logo.png $(INSTALL_DATA) $< $@ +$(HTMLDIR)/hamburger_menu.svg: hamburger_menu.svg + $(INSTALL_DATA) $< $@ + +$(HTMLDIR)/hamburger_menu_close.svg: hamburger_menu_close.svg + $(INSTALL_DATA) $< $@ + $(HTMLDIR)/grass_icon.png: grass_icon.png $(INSTALL_DATA) $< $@ diff --git a/man/grassdocs.css b/man/grassdocs.css index 6e64ee37194..9debe02d424 100644 --- a/man/grassdocs.css +++ b/man/grassdocs.css @@ -1,7 +1,7 @@ /* GRASS GIS documentation site style sheet * * send improvements to GRASS Developers list - * + * * (eg how to reach the same result on netscape, mozilla konqueror?) * * Fonts: @@ -234,3 +234,92 @@ table.compact tr:nth-child(even) { s { text-decoration-color: rgba(0, 0, 0, 0.53); } + +@media screen and (max-width: 1023.99px) { + .toc { + display: none + } +} + +@media screen and (min-width: 1023.99px) { + .toc-mobile-screen, .toc-mobile-screen:target, .hamburger { + display: none; + } +} + +.hamburger, .close { + border: none; + cursor: pointer; + position: absolute; + top: 20px; + right: 20px; + width: 32px; + height: 32px; +} + +.hamburger { + background: white; +} + +.hamburger img, .close img { + width: 100%; + height: 100%; +} + +.toc-mobile-screen { + position: absolute; + padding: 0; + margin: 0; + z-index: 1000; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; + list-style: none; + background: white; + display: flex; + flex-flow: column nowrap; + justify-content: start; + align-items: center; + transform: translateY(-100%); + transition: transform 0.2s ease; +} + +.toc-mobile-screen:target { + transform: translateY(0); +} + +.toc-mobile-screen > li > a { + display: block; + font-family: arial,sans-serif; + color: rgb(25%, 60%, 25%); + font-weight: bold; + font-size: 1.2rem; + text-decoration: none; + border-bottom: 1px solid rgb(25%, 60%, 25%); + padding-bottom: 0.5rem; + text-align: center; +} + +.toc-mobile-screen li a { + text-decoration: none; + border-bottom: 1px solid rgb(25%, 60%, 25%); + margin-bottom: 1rem; +} + +.toc-mobile-screen li { + padding-bottom: 1rem; +} + +.toc-mobile-screen li a:hover, li a:focus { + border-bottom: 2px solid rgb(25%, 60%, 25%); +} + +.toc-mobile-screen > li:first-child { + padding-top: 5rem; +} + +.toc-mobile-screen > li { + padding-top: 2rem; +} diff --git a/man/hamburger_menu.svg b/man/hamburger_menu.svg new file mode 100644 index 00000000000..3070f871480 --- /dev/null +++ b/man/hamburger_menu.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + diff --git a/man/hamburger_menu_close.svg b/man/hamburger_menu_close.svg new file mode 100644 index 00000000000..ec300f9ec06 --- /dev/null +++ b/man/hamburger_menu_close.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + X + + diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py index 8f0a3947e5b..b37d5adbe34 100644 --- a/scripts/g.extension/g.extension.py +++ b/scripts/g.extension/g.extension.py @@ -2152,9 +2152,6 @@ def check_style_file(name): dist_file = os.path.join(os.getenv("GISBASE"), "docs", "html", name) addons_file = os.path.join(options["prefix"], "docs", "html", name) - if os.path.isfile(addons_file): - return - try: shutil.copyfile(dist_file, addons_file) except OSError as error: @@ -2190,6 +2187,8 @@ def check_dirs(): create_dir(os.path.join(options["prefix"], "docs", "html")) create_dir(os.path.join(options["prefix"], "docs", "rest")) check_style_file("grass_logo.png") + check_style_file("hamburger_menu.svg") + check_style_file("hamburger_menu_close.svg") check_style_file("grassdocs.css") create_dir(os.path.join(options["prefix"], "etc")) create_dir(os.path.join(options["prefix"], "docs", "man", "man1")) diff --git a/utils/mkhtml.py b/utils/mkhtml.py index f7d9054dc16..5a44f1ff9d8 100644 --- a/utils/mkhtml.py +++ b/utils/mkhtml.py @@ -385,7 +385,6 @@ def get_last_git_commit(src_dir, addon_path, is_addon):