15 Commits

Author SHA1 Message Date
1ff82ee907 Update NEWS, bump version 2020-09-02 20:00:12 +02:00
57e92fbb85 Update copyright years 2020-09-02 20:00:11 +02:00
a04dfc59fe README: improve libasciidoc compatibility 2020-09-02 20:00:11 +02:00
7f69655c54 README: discourage from using libedit 2020-09-02 20:00:10 +02:00
444f97b357 degesch: work around a libedit attribute issue 2020-09-02 20:00:10 +02:00
ed7130a664 degesch: fix a libedit crash 2020-09-02 20:00:10 +02:00
ba1c2357af degesch: fix Lua 5.4 build
Not sure about how well it works yet.

Lua 5.3 is still made preferential by the order of pkgconfig lookup.
2020-09-02 20:00:09 +02:00
a48023553e degesch: fix a pointer operation in the libedit layer 2020-09-02 20:00:09 +02:00
d29317b29c Bump liberty 2020-09-02 20:00:09 +02:00
deb096a0e9 Name change 2020-09-02 19:37:29 +02:00
722fc48a30 CMakeLists.txt: add a comment 2020-09-02 19:37:26 +02:00
6287e20919 degesch: fix log reopening after a buffer rename 2020-03-23 00:41:08 +01:00
07d59db5ab degesch: clean up unused functions 2020-03-22 02:00:57 +01:00
2909b017fb Fix handling terminal resizes while the terminal is suspended
GNU Readline has a misfeature.
2020-03-21 22:02:02 +01:00
64d4009427 degesch: fix getpwuid usage
The "entry not found" case doesn't have to touch errno.
2019-12-07 21:18:20 +01:00
25 changed files with 79 additions and 68 deletions

View File

@@ -13,10 +13,12 @@ if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC) endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
# Version # Version
set (project_version "0.9.7") set (project_version "0.9.8")
# Try to append commit ID if it follows a version tag. It might be nicer if # Try to append commit ID if it follows a version tag. It might be nicer if
# we could also detect dirty worktrees but that's very hard to get right. # we could also detect dirty worktrees but that's very hard to get right.
# If we didn't need this for CPack, we could use add_custom_command to generate
# a version source/include file.
find_package (Git) find_package (Git)
set (git_head "${PROJECT_SOURCE_DIR}/.git/HEAD") set (git_head "${PROJECT_SOURCE_DIR}/.git/HEAD")
if (GIT_FOUND AND EXISTS "${git_head}") if (GIT_FOUND AND EXISTS "${git_head}")
@@ -83,7 +85,7 @@ include_directories (${libffi_INCLUDE_DIRS})
link_directories (${libffi_LIBRARY_DIRS}) link_directories (${libffi_LIBRARY_DIRS})
# FIXME: other Lua versions may be acceptable, don't know yet # FIXME: other Lua versions may be acceptable, don't know yet
pkg_search_module (lua lua53 lua5.3 lua-5.3 lua>=5.3) pkg_search_module (lua lua53 lua5.3 lua-5.3 lua54 lua5.4 lua-5.4 lua>=5.3)
option (WITH_LUA "Enable support for Lua plugins" ${lua_FOUND}) option (WITH_LUA "Enable support for Lua plugins" ${lua_FOUND})
if (WITH_LUA) if (WITH_LUA)
@@ -233,8 +235,8 @@ endforeach (page)
# CPack # CPack
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Experimental IRC client, daemon and bot") set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Experimental IRC client, daemon and bot")
set (CPACK_PACKAGE_VERSION "${project_version_safe}") set (CPACK_PACKAGE_VERSION "${project_version_safe}")
set (CPACK_PACKAGE_VENDOR "Premysl Janouch") set (CPACK_PACKAGE_VENDOR "Premysl Eric Janouch")
set (CPACK_PACKAGE_CONTACT "Přemysl Janouch <p@janouch.name>") set (CPACK_PACKAGE_CONTACT "Přemysl Eric Janouch <p@janouch.name>")
set (CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") set (CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set (CPACK_GENERATOR "TGZ;ZIP") set (CPACK_GENERATOR "TGZ;ZIP")

View File

@@ -1,4 +1,4 @@
Copyright (c) 2014 - 2018, Přemysl Janouch <p@janouch.name> Copyright (c) 2014 - 2020, Přemysl Eric Janouch <p@janouch.name>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted. purpose with or without fee is hereby granted.

10
NEWS
View File

@@ -1,3 +1,13 @@
0.9.8 (2020-09-02) "Yep, Still Using It"
* degesch: fixed a crash and prompt attribute output in libedit 20191231-3.1,
though users are officially discouraged from using this library
* degesch: fixed Lua 5.4 build, so far the support is experimental
* Miscellaneous little fixes
0.9.7 (2018-10-21) "Business as Usual" 0.9.7 (2018-10-21) "Business as Usual"
* kike: fix wildcard handling in WHOIS * kike: fix wildcard handling in WHOIS

View File

@@ -52,8 +52,9 @@ Not supported:
be used to implement this feature if needed be used to implement this feature if needed
- limits of almost any kind, just connections and mode `+l` - limits of almost any kind, just connections and mode `+l`
This program has been https://git.janouch.name/p/haven/src/branch/master/hid[ This program has been
ported to Go], and development continues over there. https://git.janouch.name/p/haven/src/branch/master/hid[ported to Go],
and development continues over there.
ZyklonB ZyklonB
------- -------
@@ -80,6 +81,9 @@ Runtime dependencies: openssl +
Additionally for degesch: curses, libffi, lua >= 5.3 (optional), Additionally for degesch: curses, libffi, lua >= 5.3 (optional),
readline >= 6.0 or libedit >= 2013-07-12 readline >= 6.0 or libedit >= 2013-07-12
Avoid libedit if you can, in general it works but at the moment history is
acting up and I have no clue about fixing it.
$ git clone --recursive https://git.janouch.name/p/uirc3.git $ git clone --recursive https://git.janouch.name/p/uirc3.git
$ mkdir uirc3/build $ mkdir uirc3/build
$ cd uirc3/build $ cd uirc3/build
@@ -129,6 +133,7 @@ Custom Key Bindings in degesch
------------------------------ ------------------------------
The default and preferred frontend used in 'degesch' is GNU Readline. This The default and preferred frontend used in 'degesch' is GNU Readline. This
means that you can change your bindings by editing '~/.inputrc'. For example: means that you can change your bindings by editing '~/.inputrc'. For example:
.... ....
# Preload with system-wide settings # Preload with system-wide settings
$include /etc/inputrc $include /etc/inputrc
@@ -139,6 +144,7 @@ $if degesch
"\e\e[D": move-buffer-left "\e\e[D": move-buffer-left
$endif $endif
.... ....
Consult the source code and the GNU Readline manual for a list of available Consult the source code and the GNU Readline manual for a list of available
functions. Also refer to the latter for the exact syntax of this file. functions. Also refer to the latter for the exact syntax of this file.
Beware that you can easily break the program if you're not careful. Beware that you can easily break the program if you're not careful.

View File

@@ -1,7 +1,7 @@
/* /*
* common.c: common functionality * common.c: common functionality
* *
* Copyright (c) 2014 - 2015, Přemysl Janouch <p@janouch.name> * Copyright (c) 2014 - 2015, Přemysl Eric Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted. * purpose with or without fee is hereby granted.

View File

@@ -1,7 +1,7 @@
/* /*
* degesch.c: the experimental IRC client * degesch.c: the experimental IRC client
* *
* Copyright (c) 2015 - 2018, Přemysl Janouch <p@janouch.name> * Copyright (c) 2015 - 2020, Přemysl Eric Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted. * purpose with or without fee is hereby granted.
@@ -454,6 +454,7 @@ input_rl_start (void *input, const char *program_name)
rl_readline_name = slash ? ++slash : program_name; rl_readline_name = slash ? ++slash : program_name;
rl_startup_hook = app_readline_init; rl_startup_hook = app_readline_init;
rl_catch_sigwinch = false; rl_catch_sigwinch = false;
rl_change_environment = false;
rl_basic_word_break_characters = WORD_BREAKING_CHARS; rl_basic_word_break_characters = WORD_BREAKING_CHARS;
rl_completer_word_break_characters = NULL; rl_completer_word_break_characters = NULL;
@@ -788,7 +789,8 @@ input_el__redisplay (void *input)
el_push (self->editline, x); el_push (self->editline, x);
// We have to do this or it gets stuck and nothing is done // We have to do this or it gets stuck and nothing is done
(void) el_gets (self->editline, NULL); int count = 0;
(void) el_wgets (self->editline, &count);
} }
static char * static char *
@@ -1015,7 +1017,8 @@ input_el__restore_buffer (struct input_el *self, struct input_el_buffer *buffer)
el_winsertstr (self->editline, buffer->saved_line); el_winsertstr (self->editline, buffer->saved_line);
el_cursor (self->editline, el_cursor (self->editline,
-(buffer->saved_len - buffer->saved_point)); -(buffer->saved_len - buffer->saved_point));
cstr_set (&buffer->saved_line, NULL); free (buffer->saved_line);
buffer->saved_line = NULL;
} }
} }
@@ -1086,7 +1089,6 @@ input_el_show (void *input)
return; return;
input_el__restore (self); input_el__restore (self);
// XXX: the ignore doesn't quite work, see https://gnats.netbsd.org/47539
el_set (self->editline, el_set (self->editline,
EL_PROMPT_ESC, input_el__make_prompt, INPUT_START_IGNORE); EL_PROMPT_ESC, input_el__make_prompt, INPUT_START_IGNORE);
input_el__redisplay (self); input_el__redisplay (self);
@@ -3024,18 +3026,6 @@ irc_to_utf8 (const char *text)
return str_steal (&s); return str_steal (&s);
} }
// This function is used to output debugging IRC traffic to the terminal.
// It's far from ideal, as any non-UTF-8 text degrades the entire line to
// ISO Latin 1. But it should work good enough most of the time.
static char *
irc_to_term (struct app_context *ctx, const char *text)
{
char *utf8 = irc_to_utf8 (text);
char *term = iconv_xstrdup (ctx->term_from_utf8, utf8, -1, NULL);
free (utf8);
return term;
}
// --- Output formatter -------------------------------------------------------- // --- Output formatter --------------------------------------------------------
// This complicated piece of code makes attributed text formatting simple. // This complicated piece of code makes attributed text formatting simple.
@@ -4246,11 +4236,11 @@ buffer_rename (struct app_context *ctx,
str_map_set (&ctx->buffers_by_name, buffer->name, NULL); str_map_set (&ctx->buffers_by_name, buffer->name, NULL);
str_map_set (&ctx->buffers_by_name, new_name, buffer); str_map_set (&ctx->buffers_by_name, new_name, buffer);
cstr_set (&buffer->name, xstrdup (new_name));
buffer_close_log_file (buffer); buffer_close_log_file (buffer);
buffer_open_log_file (ctx, buffer); buffer_open_log_file (ctx, buffer);
cstr_set (&buffer->name, xstrdup (new_name));
// We might have renamed the current buffer // We might have renamed the current buffer
refresh_prompt (ctx); refresh_prompt (ctx);
} }
@@ -5523,6 +5513,7 @@ irc_autofill_user_info (struct server *s, struct error **e)
return true; return true;
// Read POSIX user info and fill the configuration if needed // Read POSIX user info and fill the configuration if needed
errno = 0;
struct passwd *pwd = getpwuid (geteuid ()); struct passwd *pwd = getpwuid (geteuid ());
if (!pwd) if (!pwd)
{ {
@@ -5947,18 +5938,32 @@ on_refresh_prompt (struct app_context *ctx)
struct str prompt = str_make (); struct str prompt = str_make ();
make_prompt (ctx, &prompt); make_prompt (ctx, &prompt);
// libedit has a weird bug where it misapplies ignores when they're not
// followed by anything else, so let's try to move a trailing space,
// which will at least fix the default prompt.
const char *attributed_suffix = "";
#ifdef HAVE_EDITLINE
if (have_attributes && prompt.len && prompt.str[prompt.len - 1] == ' ')
{
prompt.str[--prompt.len] = 0;
attributed_suffix = " ";
}
#endif // HAVE_EDITLINE
char *localized = iconv_xstrdup (ctx->term_from_utf8, prompt.str, -1, NULL); char *localized = iconv_xstrdup (ctx->term_from_utf8, prompt.str, -1, NULL);
str_free (&prompt); str_free (&prompt);
if (have_attributes) if (have_attributes)
{ {
// XXX: to be completely correct, we should use tputs, but we cannot // XXX: to be completely correct, we should use tputs, but we cannot
input_maybe_set_prompt (ctx->input, xstrdup_printf ("%c%s%c%s%c%s%c", input_maybe_set_prompt (ctx->input, xstrdup_printf ("%c%s%c%s%c%s%c%s",
INPUT_START_IGNORE, ctx->attrs[ATTR_PROMPT], INPUT_START_IGNORE, ctx->attrs[ATTR_PROMPT],
INPUT_END_IGNORE, INPUT_END_IGNORE,
localized, localized,
INPUT_START_IGNORE, ctx->attrs[ATTR_RESET], INPUT_START_IGNORE, ctx->attrs[ATTR_RESET],
INPUT_END_IGNORE)); INPUT_END_IGNORE,
attributed_suffix));
free (localized); free (localized);
} }
else else
@@ -9655,12 +9660,19 @@ lua_task_resume (struct lua_task *self, int index)
n = 2; n = 2;
} }
#if LUA_VERSION_NUM >= 504
int nresults = 0;
int res = lua_resume (L, NULL, n, &nresults);
#else
int res = lua_resume (L, NULL, n); int res = lua_resume (L, NULL, n);
int nresults = lua_gettop (L);
#endif
struct error *error = NULL; struct error *error = NULL;
if (res == LUA_YIELD) if (res == LUA_YIELD)
{ {
// AFAIK we don't get any good error context information from here // AFAIK we don't get any good error context information from here
if (lua_task_schedule (self, lua_gettop (L), &error)) if (lua_task_schedule (self, nresults, &error))
return; return;
} }
// For simplicity ignore any results from successful returns // For simplicity ignore any results from successful returns
@@ -12458,6 +12470,7 @@ resume_terminal (struct app_context *ctx)
update_screen_size (); update_screen_size ();
CALL_ (ctx->input, prepare, true); CALL_ (ctx->input, prepare, true);
CALL (ctx->input, on_tty_resized);
toggle_bracketed_paste (true); toggle_bracketed_paste (true);
// In theory we could just print all unseen messages but this is safer // In theory we could just print all unseen messages but this is safer
@@ -13150,26 +13163,6 @@ app_editline_init (struct input_el *self)
// --- Configuration loading --------------------------------------------------- // --- Configuration loading ---------------------------------------------------
static struct config_item *
load_configuration_file (const char *filename, struct error **e)
{
struct config_item *root = NULL;
struct str data = str_make ();
if (!read_file (filename, &data, e))
goto end;
struct error *error = NULL;
if (!(root = config_item_parse (data.str, data.len, false, &error)))
{
error_set (e, "Parsing `%s' failed: %s", filename, error->message);
error_free (error);
}
end:
str_free (&data);
return root;
}
static const char *g_first_time_help[] = static const char *g_first_time_help[] =
{ {
"", "",

2
kike.c
View File

@@ -1,7 +1,7 @@
/* /*
* kike.c: the experimental IRC daemon * kike.c: the experimental IRC daemon
* *
* Copyright (c) 2014 - 2018, Přemysl Janouch <p@janouch.name> * Copyright (c) 2014 - 2018, Přemysl Eric Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted. * purpose with or without fee is hereby granted.

Submodule liberty updated: bb30c7d86e...1a76b2032e

View File

@@ -1,7 +1,7 @@
-- --
-- auto-rejoin.lua: join back automatically when someone kicks you -- auto-rejoin.lua: join back automatically when someone kicks you
-- --
-- Copyright (c) 2016, Přemysl Janouch <p@janouch.name> -- Copyright (c) 2016, Přemysl Eric Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted. -- purpose with or without fee is hereby granted.

View File

@@ -1,7 +1,7 @@
-- --
-- censor.lua: black out certain users' messages -- censor.lua: black out certain users' messages
-- --
-- Copyright (c) 2016, Přemysl Janouch <p@janouch.name> -- Copyright (c) 2016, Přemysl Eric Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted. -- purpose with or without fee is hereby granted.

View File

@@ -1,7 +1,7 @@
-- --
-- fancy-prompt.lua: the fancy multiline prompt you probably want -- fancy-prompt.lua: the fancy multiline prompt you probably want
-- --
-- Copyright (c) 2016, Přemysl Janouch <p@janouch.name> -- Copyright (c) 2016, Přemysl Eric Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted. -- purpose with or without fee is hereby granted.

View File

@@ -5,7 +5,7 @@
-- --
-- I call this style closure-oriented programming -- I call this style closure-oriented programming
-- --
-- Copyright (c) 2016, Přemysl Janouch <p@janouch.name> -- Copyright (c) 2016, Přemysl Eric Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted. -- purpose with or without fee is hereby granted.

View File

@@ -1,7 +1,7 @@
-- --
-- ping-timeout.lua: ping timeout readability enhancement plugin -- ping-timeout.lua: ping timeout readability enhancement plugin
-- --
-- Copyright (c) 2015 - 2016, Přemysl Janouch <p@janouch.name> -- Copyright (c) 2015 - 2016, Přemysl Eric Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted. -- purpose with or without fee is hereby granted.

View File

@@ -1,7 +1,7 @@
-- --
-- slack.lua: try to fix up UX when using the Slack IRC gateway -- slack.lua: try to fix up UX when using the Slack IRC gateway
-- --
-- Copyright (c) 2017, Přemysl Janouch <p@janouch.name> -- Copyright (c) 2017, Přemysl Eric Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted. -- purpose with or without fee is hereby granted.

View File

@@ -1,7 +1,7 @@
-- --
-- thin-cursor.lua: set a thin cursor -- thin-cursor.lua: set a thin cursor
-- --
-- Copyright (c) 2016, Přemysl Janouch <p@janouch.name> -- Copyright (c) 2016, Přemysl Eric Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted. -- purpose with or without fee is hereby granted.

View File

@@ -1,7 +1,7 @@
-- --
-- utm-filter.lua: filter out Google Analytics bullshit from URLs -- utm-filter.lua: filter out Google Analytics bullshit from URLs
-- --
-- Copyright (c) 2015, Přemysl Janouch <p@janouch.name> -- Copyright (c) 2015, Přemysl Eric Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted. -- purpose with or without fee is hereby granted.

View File

@@ -2,7 +2,7 @@
ZyklonB calc plugin, basic Scheme evaluator ZyklonB calc plugin, basic Scheme evaluator
Copyright 2016 Přemysl Janouch Copyright 2016 Přemysl Eric Janouch
See the file LICENSE for licensing information. See the file LICENSE for licensing information.
!# !#

View File

@@ -2,7 +2,7 @@
# #
# ZyklonB coin plugin, random number-based utilities # ZyklonB coin plugin, random number-based utilities
# #
# Copyright 2012, 2014 Přemysl Janouch # Copyright 2012, 2014 Přemysl Eric Janouch
# See the file LICENSE for licensing information. # See the file LICENSE for licensing information.
# #

View File

@@ -2,7 +2,7 @@
# #
# ZyklonB eval plugin, LISP-like expression evaluator # ZyklonB eval plugin, LISP-like expression evaluator
# #
# Copyright 2013, 2014 Přemysl Janouch # Copyright 2013, 2014 Přemysl Eric Janouch
# See the file LICENSE for licensing information. # See the file LICENSE for licensing information.
# #

View File

@@ -2,7 +2,7 @@
# #
# ZyklonB factoids plugin # ZyklonB factoids plugin
# #
# Copyright 2016 Přemysl Janouch <p@janouch.name> # Copyright 2016 Přemysl Eric Janouch <p@janouch.name>
# See the file LICENSE for licensing information. # See the file LICENSE for licensing information.
# #

View File

@@ -3,7 +3,7 @@
# #
# ZyklonB pomodoro plugin # ZyklonB pomodoro plugin
# #
# Copyright 2015 Přemysl Janouch # Copyright 2015 Přemysl Eric Janouch
# See the file LICENSE for licensing information. # See the file LICENSE for licensing information.
# #

View File

@@ -2,7 +2,7 @@
// //
// ZyklonB scripting plugin, using a custom stack-based language // ZyklonB scripting plugin, using a custom stack-based language
// //
// Copyright 2014 Přemysl Janouch // Copyright 2014 Přemysl Eric Janouch
// See the file LICENSE for licensing information. // See the file LICENSE for licensing information.
// //
// Just compile this file as usual (sans #!) if you don't feel like using TCC. // Just compile this file as usual (sans #!) if you don't feel like using TCC.

View File

@@ -2,7 +2,7 @@
-- --
-- ZyklonB seen plugin -- ZyklonB seen plugin
-- --
-- Copyright 2016 Přemysl Janouch <p@janouch.name> -- Copyright 2016 Přemysl Eric Janouch <p@janouch.name>
-- See the file LICENSE for licensing information. -- See the file LICENSE for licensing information.
-- --

View File

@@ -2,7 +2,7 @@
# #
# ZyklonB YouTube plugin, displaying info about YouTube links # ZyklonB YouTube plugin, displaying info about YouTube links
# #
# Copyright 2014 - 2015, Přemysl Janouch <p@janouch.name> # Copyright 2014 - 2015, Přemysl Eric Janouch <p@janouch.name>
# See the file LICENSE for licensing information. # See the file LICENSE for licensing information.
# #

View File

@@ -1,7 +1,7 @@
/* /*
* zyklonb.c: the experimental IRC bot * zyklonb.c: the experimental IRC bot
* *
* Copyright (c) 2014 - 2016, Přemysl Janouch <p@janouch.name> * Copyright (c) 2014 - 2016, Přemysl Eric Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted. * purpose with or without fee is hereby granted.