cdebconf-keystep/0000755000000000000000000000000012060235026011165 5ustar cdebconf-keystep/newt-plugin-detect-keyboard.c0000644000000000000000000002366711026237515016672 0ustar #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBTEXTWRAP #include #endif #include #include #include #include #include "detect_keys.h" #include "newt-plugin-detect-keyboard.h" static size_t strwidth(const char *width); static int strtruncate (char *what, size_t maxsize); /* * This struct may look like overkill; however it might make sense to * replace it, and press_key(), with something stateful (along the lines * of newt_progress_*). */ static struct detect_keys_frontend newt_dkf = { press_key: newt_press_key, is_key_there: newt_is_key_there, }; static const char * wait_text(struct frontend *obj) { return question_get_text(obj, "debconf/key-waiting", "Waiting %d seconds ..."); } static const char * present_text(struct frontend *obj) { return question_get_text(obj, "debconf/key-present", "Is there a key labelled '%s' ?"); } static const char * present_plain_text(struct frontend *obj) { return question_get_text(obj, "debconf/key-present-plain", "Is there a key labelled '%s' ? Only count labels for the key on its own or with Shift, not with Alt or other modifier keys."); } static const char * delay_text(struct frontend *obj) { return question_get_text(obj, "debconf/key-delay", "30"); } static const char * wrong_text(struct frontend *obj) { return question_get_text(obj, "debconf/key-wrong", "Keycode %d was not expected -- ignored.\nNo need to press Shift or other modifier keys."); } static const char * keypress_text(struct frontend *obj) { return question_get_text(obj, "debconf/key-press", "Please press one of these keys: %s"); } static const char * yes_text(struct frontend *obj) { return question_get_text(obj, "debconf/button-yes", "Yes"); } static const char * no_text(struct frontend *obj) { return question_get_text(obj, "debconf/button-no", "No"); } static int newt_press_key(struct frontend *obj, char *syms, int *codes, int *result) { int width = 80, win_width; #ifdef HAVE_LIBTEXTWRAP int flags = 0; #else int flags = NEWT_FLAG_WRAP; #endif int state = atoi(delay_text(obj))+1; /* timer -- 0=done, -1=error */ newtComponent form, prompt, prompt2, delay; char *request, *dtitle; struct termios old,new, old0,new0; int oldkbmode; unsigned char buf[64]; int i, len, j, fd; struct pollfd pfd = { fd:0, events:POLLIN }; int ret = DC_NOTOK; int last_code = -1; newtGetScreenSize(&width, NULL); win_width = width-7; newtCenteredWindow(win_width, 9, obj->title); prompt = newtTextbox(TEXT_PADDING, 2, win_width-2*TEXT_PADDING, 2, flags); assert(prompt); prompt2 = newtTextbox(TEXT_PADDING, 4, win_width-2*TEXT_PADDING, 2, flags); assert(prompt2); delay = newtTextbox(TEXT_PADDING, 6, win_width-2*TEXT_PADDING, 2, flags); assert(delay); form = cdebconf_newt_create_form(NULL); assert(form); asprintf(&request, keypress_text(obj), syms); newtTextboxSetText(prompt, request); free(request); newtFormAddComponents(form, prompt, prompt2, delay, NULL); dtitle=malloc(1000); sprintf(dtitle, "Do %s --", syms); for(j=0; codes[j] != -1; j++) sprintf(dtitle+strlen(dtitle)," %02x",codes[j]); free(dtitle); /* Set the console to emit "standard" Linux keycodes. We don't know * what mode console and/or standard input is in at the moment, so * take care to save+restore everything. * * Note that the actual reading is still done through standard * input, via bterm. */ fd = open("/dev/console", O_RDWR); if (fd == -1) fd = 0; if (tcgetattr(0, &old0) == -1) state = -1; if (tcgetattr(0, &new0) == -1) state = -1; if (tcgetattr(fd, &old) == -1) state = -1; if (tcgetattr(fd, &new) == -1) state = -1; if (ioctl(fd, KDGKBMODE, &oldkbmode)) state = -1; new.c_lflag &= ~ (ICANON | ECHO | ISIG); new.c_iflag = 0; new.c_cc[VMIN] = 0; new.c_cc[VTIME] = 0; if (state > 0 && tcsetattr(fd, TCSAFLUSH, &new) == -1) state = -1; if (state > 0 && ioctl(fd, KDSKBMODE, K_MEDIUMRAW)) state = -1; new0.c_lflag &= ~ (ICANON | ECHO | ISIG); new0.c_iflag = 0; new0.c_cc[VMIN] = 0; new0.c_cc[VTIME] = 0; if (state > 0 && tcsetattr(0, TCSAFLUSH, &new0) == -1) state = -1; /* Now do the actual work. * state=0: found a keycode that's OK. */ while(state > 0) { state -= 1; /* Annoy people every ten seconds */ if(state<10 || !(state%10)) { asprintf(&dtitle, wait_text(obj), state); newtTextboxSetText(delay, dtitle); free(dtitle); } newtDrawForm(form); newtRefresh(); switch(poll(&pfd,1,1000)) { case 0: /* timed out */ break; case 1: len = read(0, buf, sizeof(buf)); if (len<1) break; for(i=0; state && ititle, win_width-9); #ifdef HAVE_LIBTEXTWRAP textwrap_init(&tw); textwrap_columns(&tw, win_width - 2 - 2*TEXT_PADDING); wrappedtext = textwrap(&tw, full_description); free(full_description); full_description = wrappedtext; #endif if (full_description != NULL) { t_height = cdebconf_newt_get_text_height(full_description, win_width); } else t_height = 0; if (t_height + 4 <= height-5) win_height = t_height + 4; else { win_height = height-5; flags |= NEWT_FLAG_SCROLL; t_width_scroll = 2; } t_height = win_height - 4; t_width = cdebconf_newt_get_text_width(full_description); t_width_buttons = 2*BUTTON_PADDING; t_width_buttons += cdebconf_newt_get_text_width(yes_text(obj)) + 3; t_width_buttons += cdebconf_newt_get_text_width(no_text(obj)) + 3; if (t_width_buttons > t_width) t_width = t_width_buttons; if (win_width > t_width + 2*TEXT_PADDING + t_width_scroll) win_width = t_width + 2*TEXT_PADDING + t_width_scroll; t_width_title = cdebconf_newt_get_text_width(obj->title); if (t_width_title > win_width) win_width = t_width_title; cdebconf_newt_create_window(win_width, win_height, obj->title, NULL); form = cdebconf_newt_create_form(NULL); textbox = newtTextbox(TEXT_PADDING, 1, t_width, t_height, flags); assert(textbox); if (full_description != NULL) newtTextboxSetText(textbox, full_description); free(full_description); bYes = newtCompactButton(TEXT_PADDING + BUTTON_PADDING - 1, win_height-2, yes_text(obj)); bNo = newtCompactButton(win_width - TEXT_PADDING - BUTTON_PADDING - strwidth(no_text(obj)) - 3, win_height-2, no_text(obj)); newtFormAddComponents(form, textbox, bYes, bNo, NULL); newtFormSetCurrent(form, bNo); cRet = newtRunForm(form); if (cRet == bYes) { ret = DC_OK; *result = true; } else if (cRet == bNo) { ret = DC_OK; *result = false; } else ret = DC_NOTOK; newtFormDestroy(form); newtPopWindow(); return ret; } int cdebconf_newt_handler_detect_keyboard(struct frontend *obj, struct question *q) { char *result, *filename; int res; filename = q_get_choices(obj, q); if (!filename || !*filename) return DC_NOTOK; res = detect_keys(obj, &newt_dkf, filename, &result); if (res != DC_OK) return res; question_setvalue(q, result); return DC_OK; } int strtruncate (char *what, size_t maxsize) { size_t pos; int k; char *p; wchar_t c; if (strwidth(what) <= maxsize) return 0; /* Replace end of string with ellipsis "..."; as the last character * may have a double width, stops 4 characters before the end */ pos = 0; for (p = what; (k = mbtowc (&c, p, MB_LEN_MAX)) > 0 && pos < maxsize-5; p += k) pos += wcwidth (c); for (k=0; k < 3; k++, p++) *p = '.'; *p = '\0'; return 1; } size_t strwidth (const char *what) { size_t res; int k; const char *p; wchar_t c; for (res = 0, p = what ; (k = mbtowc (&c, p, MB_LEN_MAX)) > 0 ; p += k) res += wcwidth (c); return res; } cdebconf-keystep/detect_keys.c0000644000000000000000000001632111026240520013633 0ustar /** * @file detect_keys.c * @brief sub-interface to select keyboards */ #include #include #include #include #include #include #include "detect_keys.h" #define MODULE "detect-keys" #define debug(fmt, args...) syslog(LOG_DEBUG, MODULE ": " fmt, ##args) enum step_type { step_unknown, step_press_key, step_key_present, step_key_present_plain, step_result }; struct stepdata { FILE *step_file; int current_step; enum step_type type; char *symbols; /* doubles as the keymap name */ int *next_steps; /* zero-terminated */ int *keycodes; /* same length */ }; static void stepdata_delete (struct stepdata *sd); static struct stepdata * stepdata_new (char *filename) { struct stepdata *sd; sd = NEW(struct stepdata); sd->symbols = NEW(char); *sd->symbols = '\0'; sd->next_steps = NEW(int); *sd->next_steps = -1; sd->keycodes = NEW(int); *sd->keycodes = -1; sd->step_file = fopen(filename, "r"); if (sd->step_file == NULL) { debug("File '%s' open error: %m", filename); stepdata_delete(sd); return NULL; } sd->current_step = -1; sd->type = step_unknown; return sd; } static void stepdata_delete (struct stepdata *sd) { if (sd == NULL) return; if (sd->step_file) fclose(sd->step_file); free (sd->next_steps); free (sd->keycodes); free (sd->symbols); DELETE(sd); } /* Quick hacks to deal with integer lists */ static int iv_len (int *vec) { int len = 0; if (vec == NULL) return 0; while(*vec != -1) { len++; vec++; } return len; } static void iv_add (int **vec, int num) { int len = iv_len(*vec); *vec = realloc(*vec, sizeof(int *)*(len+2)); (*vec)[len] = num; (*vec)[len+1] = -1; return; } /* ditto string */ /* Actually fetch the Next Thing To DO */ static int read_step (int step, struct stepdata *data) { char buf[256]; char *p; data->type = step_unknown; *data->symbols = '\0'; *data->next_steps = -1; *data->keycodes = -1; while(1) { p = fgets(buf, sizeof(buf), data->step_file); /* If we're leaving the currently-requested step, return OK * on enf-of-file or when the step number changes. */ if (p == NULL) { /* error or end of file */ if (feof(data->step_file) && (data->current_step == step)) return DC_OK; return DC_NOTOK; } p[strlen(p)-1] = '\0'; /* kill the newline */ if (strncmp(buf,"STEP ",5) == 0) { if (data->current_step == step) { data->current_step = atoi(buf+5); return DC_OK; } data->current_step = atoi(buf+5); } else if(data->current_step != step) { /* ignore everything non-interesting */ continue; } else if (strncmp(buf,"PRESS ",6) == 0) { /* PRESS symbol */ int len; if (data->type == step_unknown) data->type = step_press_key; else if (data->type != step_press_key) { debug("Line sequence error: %s", buf); return DC_NOTOK; } len = strlen(data->symbols); data->symbols = realloc(data->symbols,len+strlen(buf)-4); if (len) strcat(data->symbols, " "); strcat(data->symbols, buf+6); } else if (strncmp(buf,"CODE ",5) == 0) { /* CODE keycode nextstep */ char *skip; if (data->type != step_press_key) { debug("Line sequence error: %s", buf); return DC_NOTOK; } skip = strchr(buf+5,' '); iv_add (&data->next_steps, atoi(skip)); iv_add (&data->keycodes, atoi(buf+5)); } else if (strncmp(buf,"FIND ",5) == 0) { /* FIND symbol */ int len; if (data->type == step_unknown) data->type = step_key_present; else { debug("Line sequence error: %s", buf); return DC_NOTOK; } len = strlen(buf+5); data->symbols = realloc(data->symbols, len+1); strcpy(data->symbols, buf+5); } else if (strncmp(buf,"FINDP ",6) == 0) { /* FINDP symbol */ int len; if (data->type == step_unknown) data->type = step_key_present_plain; else { debug("Line sequence error: %s", buf); return DC_NOTOK; } len = strlen(buf+6); data->symbols = realloc(data->symbols, len+1); strcpy(data->symbols, buf+6); } else if (strncmp(buf,"YES ",4) == 0) { /* YES stepnr */ if (data->type != step_key_present && data->type != step_key_present_plain) { debug("Line sequence error: %s", buf); return DC_NOTOK; } while (iv_len(data->next_steps) < 2) iv_add(&data->next_steps,-2); data->next_steps[1] = atoi(buf+4); } else if (strncmp(buf,"NO ",3) == 0) { /* NO stepnr */ if (data->type != step_key_present && data->type != step_key_present_plain) { debug("Line sequence error: %s", buf); return DC_NOTOK; } if (iv_len(data->next_steps) < 1) iv_add(&data->next_steps,-2); data->next_steps[0] = atoi(buf+3); } else if (strncmp(buf,"MAP ",4) == 0) { /* MAP name */ int len; if (data->type == step_unknown) data->type = step_result; else { debug("Line sequence error: %s", buf); return DC_NOTOK; } len = strlen(buf+4); data->symbols = realloc(data->symbols, len+1); strcpy(data->symbols, buf+4); } else { /* duh */ debug("Unknown line: %s", buf); return DC_NOTOK; } } } int detect_keys(struct frontend *obj, struct detect_keys_frontend *methods, char *filename, char **result) { int step = 0; int res; struct stepdata *data; data = stepdata_new(filename); if (!data) return DC_NOTOK; if (data->step_file == NULL) { stepdata_delete(data); return DC_NOTOK; } while(1) { syslog(LOG_INFO,"BLURB5"); res = read_step(step, data); syslog(LOG_INFO,"BLURB6"); if (res != DC_OK) { stepdata_delete(data); return res; } if (data->type == step_press_key) { int code,i,len; len = iv_len(data->keycodes); code = -1; res = (*methods->press_key)(obj,data->symbols,data->keycodes,&code); syslog(LOG_INFO,"BLURB"); if (res != DC_OK) { stepdata_delete(data); return res; } for (i=0; i < len; i++) { if (data->keycodes[i] == code) break; } syslog(LOG_INFO,"BLURB2"); if (i == len) { stepdata_delete(data); syslog(LOG_ERR, "Keycode not found: %d", code); return DC_NOTOK; } syslog(LOG_INFO,"BLUR3"); step = data->next_steps[i]; syslog(LOG_INFO,"BLURB4"); } else if (data->type == step_key_present || data->type == step_key_present_plain) { bool is_present; syslog(LOG_INFO,"BLURB7"); res = (*methods->is_key_there)( obj, data->symbols, data->type == step_key_present_plain, &is_present); syslog(LOG_INFO,"BLURB8"); if (res != DC_OK) { stepdata_delete(data); return res; } step = data->next_steps[is_present ? 1 : 0]; } else if (data->type == step_result) { syslog(LOG_INFO,"BLURB9"); *result = data->symbols; data->symbols = NULL; /* to avoid having it freed ... */ stepdata_delete(data); syslog(LOG_INFO, "return %s", *result); return DC_OK; } else { syslog(LOG_ERR, "Unknown step type: %d",data->type); stepdata_delete(data); return DC_NOTOK; } } /* NOTREACHED */ } cdebconf-keystep/Makefile.in0000644000000000000000000000165012060235005013231 0ustar prefix=@prefix@ etcdir=@sysconfdir@ bindir=${prefix}/bin sbindir=${prefix}/sbin libdir=${prefix}/lib moddir=${libdir}/cdebconf/frontend sharedir=${prefix}/share/debconf mandir=${prefix}/share/man incdir=${prefix}/include/cdebconf PACKAGE=@PACKAGE@ CC=@CC@ CFLAGS=@CFLAGS@ -I. @DEFS@ LIBS=@LIBS@ -lnewt FRONTENDS=@FRONTENDS@ PLUGIN_MODULES=$(addsuffix -plugin-$(PACKAGE).so,$(FRONTENDS)) all: $(PLUGIN_MODULES) install: $(PLUGIN_MODULES) for p in $(PLUGIN_MODULES); do \ install -m755 -d $(DESTDIR)/$(moddir)/$${p%%-*} ; \ install -m644 $$p $(DESTDIR)/$(moddir)/$${p%%-*}/$${p#*-} ; \ done newt-plugin-$(PACKAGE).so: newt-plugin-$(PACKAGE).opic detect_keys.opic $(CC) -shared $(LIBS) -o $@ newt-plugin-$(PACKAGE).opic detect_keys.opic clean: rm -f $(PLUGIN_MODULES) rm -f *.opic distclean: clean rm -f config.log config.status rm -f Makefile %.opic: %.c @echo "Compiling $< to $@" $(CC) $(CFLAGS) -fPIC -o $@ -c $< cdebconf-keystep/configure.ac0000644000000000000000000000127110515516337013466 0ustar AC_INIT(detect_keys.c) PACKAGE=detect-keyboard AC_DEFINE_UNQUOTED(PACKAGE,"$PACKAGE") AC_PROG_MAKE_SET AC_PROG_CC dnl Enable debugging? AC_ARG_WITH([debug], AS_HELP_STRING([--without-debug], [turn off debugging])) if test "$with_debug" != "no"; then AC_DEFINE(DODEBUG) CFLAGS="$CFLAGS -g -D_DEBUG_" fi dnl Use libtextwrap? AC_ARG_WITH([textwrap], AS_HELP_STRING([--without-textwrap], [don't use libtextwrap for line-folding])) if test "$with_textwrap" != "no"; then AC_CHECK_LIB([textwrap], [textwrap_init]) fi AC_CHECK_LIB(newt, newtInit, FRONTENDS="$FRONTENDS newt", echo "*** Cannot build Newt plugin ***") AC_SUBST(FRONTENDS) AC_SUBST(PACKAGE) AC_OUTPUT(Makefile) cdebconf-keystep/detect_keys.h0000644000000000000000000000105510513313567013652 0ustar /** * @file detect_keys.h * @brief sub-interface to select keyboards */ #ifndef _DETECT_KEYS_H_ #define _DETECT_KEYS_H_ #include #undef _ #define _(x) (x) #define DCF_CAPB_BACKUP (1UL << 0) struct frontend; struct detect_keys_frontend { int (*press_key)(struct frontend *, char *syms, int *codes, int *result); int (*is_key_there)(struct frontend *, char *sym, bool plain, bool *result); }; int detect_keys(struct frontend *obj, struct detect_keys_frontend *methods, char *filename, char **result); #endif /* DETECT_KEYS_H */ cdebconf-keystep/newt-plugin-detect-keyboard.h0000644000000000000000000000046010723551236016663 0ustar #ifndef _NEWT_PLUGIN_DETECT_KEYBOARD_H_ #define _NEWT_PLUGIN_DETECT_KEYBOARD_H_ static int newt_press_key(struct frontend *obj, char *syms, int *codes, int *result); static int newt_is_key_there(struct frontend *obj, char *sym, bool plain, bool *result); #endif /* _NEWT_PLUGIN_DETECT_KEYBOARD_H_ */ cdebconf-keystep/debian/0000755000000000000000000000000012060235364012414 5ustar cdebconf-keystep/debian/changelog0000644000000000000000000000525112060235362014267 0ustar cdebconf-keystep (0.12) raring; urgency=low * Link with $(CC) rather than gcc, fixing cross-building. -- Colin Watson Fri, 07 Dec 2012 00:40:17 +0000 cdebconf-keystep (0.11) raring; urgency=low * Use dh-autoreconf to avoid huge diffs when the autotools are updated. -- Colin Watson Tue, 04 Dec 2012 00:22:14 +0000 cdebconf-keystep (0.10) lucid; urgency=low * Convert to debhelper v7. -- Colin Watson Fri, 26 Feb 2010 21:04:10 +0000 cdebconf-keystep (0.9) intrepid; urgency=low * Update q_get_choices call to the API in cdebconf (>= 0.129). * debug_printf no longer seems to be exported by cdebconf; define our own debugging macro instead. -- Colin Watson Wed, 18 Jun 2008 18:10:04 +0100 cdebconf-keystep (0.8) hardy; urgency=low * Reupload without vim swap file cruft in the source tarball. Sorry! -- Colin Watson Thu, 29 Nov 2007 16:52:14 +0000 cdebconf-keystep (0.7) hardy; urgency=low * Port fixes from cdebconf-entropy (LP: #172807): - Switch the handler symbol to the "cdebconf_" namespace. - Use the proper namespace to access newt frontend API. - Remove the usage of dlsym() and dlopen() now that frontend symbols are loaded globally. - Bump Depends on cdebconf accordingly. * Change Maintainer to ubuntu-installer@lists.ubuntu.com. * Add Vcs-Bzr field. * Fix Section. * Fix configure options so that it doesn't always think we're cross-compiling. * Remove unused debhelper command cruft. -- Colin Watson Thu, 29 Nov 2007 16:32:50 +0000 cdebconf-keystep (0.6) edgy; urgency=low * Build with libtextwrap (closes: Malone #66817). -- Colin Watson Thu, 19 Oct 2006 00:17:57 +0100 cdebconf-keystep (0.5) edgy; urgency=low * Accept YES and NO in step_key_present_plain state. -- Colin Watson Tue, 17 Oct 2006 10:25:26 +0100 cdebconf-keystep (0.4) edgy; urgency=low * Handle new FINDP command from keymapper 0.5.3-7. * Include for atoi. -- Colin Watson Thu, 12 Oct 2006 02:19:35 +0100 cdebconf-keystep (0.3) dapper; urgency=low * Make sure to compile with -fPIC to work correctly on amd64 and such. -- Tollef Fog Heen Wed, 4 Jan 2006 10:59:33 +0100 cdebconf-keystep (0.2) dapper; urgency=low * Upload without binaries in the .tar.gz * Make into a native package. -- Tollef Fog Heen Wed, 4 Jan 2006 09:13:52 +0100 cdebconf-keystep (0.1-1) dapper; urgency=low * Initial release. -- Tollef Fog Heen Wed, 16 Nov 2005 13:57:01 +0100 cdebconf-keystep/debian/rules0000755000000000000000000000035612057240713013500 0ustar #! /usr/bin/make -f %: dh $@ --with autoreconf CFLAGS = -Wall -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif override_dh_auto_configure: CFLAGS="$(CFLAGS) -Wl,-z,defs" dh_auto_configure cdebconf-keystep/debian/compat0000644000000000000000000000000211342032540013603 0ustar 7 cdebconf-keystep/debian/control0000644000000000000000000000136312057240102014012 0ustar Source: cdebconf-keystep Priority: optional Maintainer: Ubuntu Installer Team Build-Depends: debhelper (>= 7.0.50~), dh-autoreconf, libdebconfclient0-dev (>= 0.129), libnewt-dev, libtextwrap-dev (>= 0.1-5) Standards-Version: 3.6.2 Section: debian-installer Vcs-Bzr: http://bazaar.launchpad.net/~ubuntu-core-dev/cdebconf-keystep/ubuntu Package: cdebconf-newt-detect-keys XC-Package-Type: udeb XB-Debconf-Frontend: newt Architecture: any Provides: cdebconf-detect-keys Depends: ${shlibs:Depends}, ${misc:Depends} Description: cdebconf plugin to detect keyboard layout This is the newt plugin used for keyboard detection. It should be pulled in automatically by kbd-chooser, so you should never see this description. cdebconf-keystep/debian/copyright0000644000000000000000000000305110355562550014353 0ustar This package was debianized by Tollef Fog Heen on Wed, 16 Nov 2005 13:57:01 +0100. It was based on the keyboard autodetection widget code from cdebconf in Ubuntu written by Matthias Urlichs . Copyright Holder: Randolph Chung Canonical Limited and others License: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.