Compare commits

..

No commits in common. "master" and "20170417-1" have entirely different histories.

27 changed files with 451 additions and 273 deletions

2
.gitignore vendored Executable file → Normal file
View File

@ -1,5 +1,3 @@
.DS_Store
._.DS_Store
*.class
wordsearch.war
wordsearch.jar

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 Matthew Slowe
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

37
Makefile Normal file → Executable file
View File

@ -1,34 +1,31 @@
JAVA = /usr/bin/java
LIBS = .:war/WEB-INF/lib/commons-lang.jar:war/WEB-INF/lib/sqlite-jdbc.jar
# JAVAFLAGS = -version # -classpath $(LIBS)
JAVAC = /usr/bin/javac
JFLAGS = -g -classpath $(LIBS)
JFLAGS = -g # -classpath $(LIBS)
SRCS = uk/org/mafoo/wordsearch/CouldNotPlaceWordException.java \
uk/org/mafoo/wordsearch/Bounds.java \
uk/org/mafoo/wordsearch/GridFactory.java \
uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java \
uk/org/mafoo/wordsearch/Direction.java
JSPS = $(wildcard war/*.jsp war/*.css war/WEB-INF/jspf/*.jspf)
SRCS = uk/org/mafoo/wordsearch/GridFactory.java \
uk/org/mafoo/wordsearch/Bounds.java \
uk/org/mafoo/wordsearch/CouldNotPlaceWordException.java \
uk/org/mafoo/wordsearch/Direction.java \
uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java
OBJS = ${SRCS:.java=.class}
.SUFFIXES: .java .class
.PHONY: default clean
default: wordsearch.war
all: build wordsearch.jar
clean:
rm -f $(OBJS) wordsearch.jar wordsearch.war
run: all
$(JAVA) uk.org.mafoo.wordsearch.GridFactory 30 30
.java.class:
$(JAVAC) $(JFLAGS) $<
wordsearch.jar: $(OBJS)
build: $(OBJS)
clean:
rm -f $(OBJS) wordsearch.jar wordsearch.war
wordsearch.jar: build
jar cf $@ $(OBJS)
war/WEB-INF/lib/wordsearch.jar: wordsearch.jar
cp $< $@
wordsearch.war: war/WEB-INF/lib/wordsearch.jar $(JSPS)
jar -cvf $@ -C war .
cp wordsearch.jar war/WEB-INF/lib

11
README.md Executable file → Normal file
View File

@ -12,4 +12,15 @@ A simple ```Makefile``` is provided:
$ make
```
Once built, you need to make a "war" file to deploy to your J2EE container (tested on Tomcat)
```
$ cd war && jar cfv ../wordsearch.war .
```
Then deploy your war file :-)
Alternatively you can test-run the engine...
```
$ make run <wordlist.txt
```

View File

@ -1 +0,0 @@
CREATE TABLE grids (id integer primary key, ts timestamp default current_timestamp, remotehost varchar, input, size_x int, size_y int, simple tinyint, result varchar);

12
src/Makefile Normal file
View File

@ -0,0 +1,12 @@
CC=gcc
CFLAGS=-DDEBUG_GRID_MAIN -std=c99 -g
DEPS=dir.o rnd.o grid.o
wordsearch: $(DEPS)
$(CC) -o wordsearch $(DEPS) $(CFLAGS)
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
clean:
rm $(DEPS)

39
src/dir.c Normal file
View File

@ -0,0 +1,39 @@
#include "dir.h"
#include "rnd.h"
int directions[] = {
DIRECTION_N,
DIRECTION_NE,
DIRECTION_E,
DIRECTION_SE,
DIRECTION_S,
DIRECTION_SW,
DIRECTION_W,
DIRECTION_NW
};
int get_direction(int simple)
{
if (simple) {
if (random_number(0, 1) == 0) {
return DIRECTION_E;
} else {
return DIRECTION_S;
}
} else {
return directions[random_number(0, NUM_DIRECTIONS)];
}
}
#ifdef DEBUG_DIR_MAIN
#include <stdio.h>
int main()
{
int n = 32;
while (--n > 0) {
printf("%d\n", get_direction(1));
}
return 0;
}
#endif

19
src/dir.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef WORDSEARCH_DIR
#define WORDSEARCH_DIR
enum direction {
DIRECTION_N,
DIRECTION_NE,
DIRECTION_E,
DIRECTION_SE,
DIRECTION_S,
DIRECTION_SW,
DIRECTION_W,
DIRECTION_NW
};
#define NUM_DIRECTIONS 8
int get_direction(int simple);
#endif

197
src/grid.c Executable file
View File

@ -0,0 +1,197 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include "rnd.h"
#include "dir.h"
#include "grid.h"
enum exitcodes {
EXIT_WORDTOOLONG,
};
bounds *get_bounds(int height, int width, enum direction direction, int length)
{
if (length > height || length > width) {
return NULL;
}
length--;
bounds *b = (bounds *) malloc(sizeof(bounds));
b->min_x = 0;
b->max_x = width-1;
b->min_y = 0;
b->max_y = height-1;
if (direction == DIRECTION_N ||
direction == DIRECTION_NE || direction == DIRECTION_NW) {
b->min_y = length;
}
if (direction == DIRECTION_W ||
direction == DIRECTION_NW || direction == DIRECTION_SW) {
b->min_x = length;
}
if (direction == DIRECTION_E ||
direction == DIRECTION_NE || direction == DIRECTION_SE) {
b->max_x = width - length;
}
if (direction == DIRECTION_S ||
direction == DIRECTION_SW || direction == DIRECTION_SE) {
b->max_y = height - length;
}
return b;
}
int move_x(int x, enum direction d) {
if(
d == DIRECTION_E ||
d == DIRECTION_NE ||
d == DIRECTION_SE
) {
x++;
} else if (
d == DIRECTION_W ||
d == DIRECTION_NW ||
d == DIRECTION_SW
) {
x--;
}
return x;
}
int move_y(int y, enum direction d) {
if(
d == DIRECTION_N ||
d == DIRECTION_NE ||
d == DIRECTION_NW
) {
y--;
} else if (
d == DIRECTION_S ||
d == DIRECTION_SE ||
d == DIRECTION_SW
) {
y++;
}
return y;
}
char **make_grid(char **words, int height, int width, int simple, int count)
{
char **grid = init_grid(NULL, height, width);
for(int i=0; i<count; i++) {
int tries = 0;
int placed = 0;
while(tries++ < WORDSEARCH_MAXTRIES && placed == 0) {
if(place_word(words[i], grid, height, width, simple)) {
placed = 1;
}
}
}
return grid;
}
int place_word(char *word, char **grid, int height, int width, int simple)
{
int dir = get_direction(simple);
bounds *b;
if (b = get_bounds(height, width, dir, strlen(word))) {
/* word will probably fit... */
int x, y;
x = random_number(b->min_x, b->max_x);
y = random_number(b->min_y, b->max_y);
char** tempgrid = init_grid(grid, height, width);
/* Now we have two copies of the grid, try to place the word... */
int i;
for(i=0; i<strlen(word); i++) {
if(!isalpha(word[i])) continue;
if(tempgrid[y][x] != '_') {
if(tempgrid[y][x] != word[i]) {
/* Failed to place word */
free_grid(tempgrid, height);
return 0;
} else {
/* word crossed ok! */
}
} else {
tempgrid[y][x] = word[i];
}
x = move_x(x, dir);
y = move_y(y, dir);
}
free_grid(grid, height);
free(b);
grid = tempgrid;
return 1;
} else {
/* word can't fit */
printf("[ERR] Word too long to place in this grid: %s\n", word);
exit(EXIT_WORDTOOLONG);
}
}
/* Clones or creates an empty grid - pass NULL in as old to get an empty grid */
char **init_grid(char** old, int height, int width)
{
int row, cell;
char **new = malloc(height * sizeof(char*));
for (row=0; row < height; row++) {
new[row] = malloc(width * sizeof(char));
for (cell=0; cell < width; cell++) {
if(old) {
new[row][cell] = old[row][cell];
} else {
new[row][cell] = '_';
}
}
}
return new;
}
void free_grid(char** grid, int height) {
for (int i=0; i<height; i++) {
free(grid[i]);
}
free(grid);
}
void print_grid(char** grid, int height) {
for(int i=0; i<height; i++) {
if(grid[i] == NULL) {
printf("row error\n");
} else {
printf("%s\n", grid[i]);
}
}
}
#ifdef DEBUG_GRID_MAIN
#include <stdio.h>
int main()
{
char *words[4] = {
"test",
"word",
"longer",
"verylong"
};
char **grid = make_grid(words, 10, 10, 0, 4);
print_grid(grid, 4);
}
#endif

26
src/grid.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef WORDSEARCH_GRID
#define WORDSEARCH_GRID
#define WORDSEARCH_MAXTRIES 500
char **make_grid(char **words, int height, int width, int simple, int count);
typedef struct bounds {
int min_y;
int max_y;
int min_x;
int max_x;
} bounds;
/* returns NULL if cannot fit word; caller needs to free() the response */
bounds *get_bounds(int height, int width, enum direction direction, int length);
int place_word(char *word, char **grid, int height, int width, int simple);
char **init_grid(char** old, int height, int width);
void free_grid(char** grid, int height);
int move_x(int x, enum direction d);
int move_y(int y, enum direction d);
void print_grid(char** grid, int height);
#endif

90
src/rnd.c Normal file
View File

@ -0,0 +1,90 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "rnd.h"
/* https://www.math.cornell.edu/~mec/2003-2004/cryptography/subs/frequencies.html */
#define ALPHABET_SIZE 26
#define RND_MAXINT 10000
struct letter_frequency {
int p; /* pegged to 10000 rather than 1 */
char c;
} letter_frequencies[] = {
{
7, 'Z'}, {
10, 'J'}, {
11, 'Q'}, {
17, 'X'}, {
69, 'K'}, {
111, 'V'}, {
149, 'B'}, {
182, 'P'}, {
203, 'G'}, {
209, 'W'}, {
211, 'Y'}, {
230, 'F'}, {
261, 'M'}, {
271, 'C'}, {
288, 'U'}, {
398, 'L'}, {
432, 'D'}, {
592, 'H'}, {
602, 'R'}, {
628, 'S'}, {
695, 'N'}, {
731, 'I'}, {
768, 'O'}, {
812, 'A'}, {
910, 'T'}, {
1202, 'E'},};
/* from http://stackoverflow.com/questions/822323/how-to-generate-a-random-number-in-c */
int random_number(int min_num, int max_num)
{
static int initialised = 0;
int result = 0;
int low_num = 0;
int hi_num = 0;
if (min_num < max_num) {
low_num = min_num;
hi_num = max_num + 1; // this is done to include max_num in output.
} else {
low_num = max_num + 1; // this is done to include max_num in output.
hi_num = min_num;
}
if (!initialised) {
srand(time(NULL));
initialised = 1;
}
result = (rand() % (hi_num - low_num)) + low_num;
return result;
}
char get_random_letter()
{
int rnd = random_number(0, RND_MAXINT);
for (int i = 0; i < ALPHABET_SIZE; i++) {
if (rnd < letter_frequencies[i].p) {
return letter_frequencies[i].c;
}
rnd -= letter_frequencies[i].p;
}
return '\0';
}
#ifdef DEBUG_RND_MAIN
#include <stdio.h>
int main()
{
int n = 32;
while (--n > 0) {
printf("%c", get_random_letter());
}
return 0;
}
#endif

7
src/rnd.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef WORDSEARCH_RND
#define WORDSEARCH_RND
char get_random_letter();
int random_number(int min_num, int max_num);
#endif

View File

@ -1,9 +0,0 @@
Kitchen
Lounge
Study
Ballroom
Conservatory
Billiard Room
Library
Hall
Dining Room

0
uk/org/mafoo/wordsearch/Direction.java Executable file → Normal file
View File

View File

@ -6,7 +6,7 @@ import java.util.*;
public class GridFactory {
static Random rnd = new Random();
static final int MAX_TRIES = 5000;
static final int MAX_TRIES = 500;
/* https://www.math.cornell.edu/~mec/2003-2004/cryptography/subs/frequencies.html */
static DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
@ -37,7 +37,7 @@ public class GridFactory {
drng.addNumber(23, 0.0017d); // X
drng.addNumber(24, 0.0211d); // Y
drng.addNumber(25, 0.0007d); // Z
}
}
private static char[] chars = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
@ -77,10 +77,10 @@ public class GridFactory {
Bounds b = new Bounds(0, height, 0, width);
length--; // arrays, duh
if(
direction == Direction.N ||
direction == Direction.NE ||
direction == Direction.N ||
direction == Direction.NE ||
direction == Direction.NW
) {
b.min_y = length;
@ -158,10 +158,6 @@ public class GridFactory {
return makeGrid(words, height, width, false, true);
}
public static char[][] makeGrid(List<String> words, int height, int width, boolean simple) {
return makeGrid(words, height, width, simple, true);
}
public static char[][] makeGrid(List<String> words, int height, int width, boolean simple, boolean fill) {
char[][] grid = new char[height][width];
@ -188,7 +184,7 @@ public class GridFactory {
if(fill) {
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
if (grid[y][x] == Character.UNASSIGNED)
if (grid[y][x] == Character.UNASSIGNED)
// grid[y][x] = '_';
grid[y][x] = getRandomChar();
}
@ -202,7 +198,7 @@ public class GridFactory {
Direction direction = getDirection(simple);
Bounds b = getBounds(grid.length, grid[0].length, direction, word.length());
// System.out.println("[" + word + "] bounds: " + b);
int x = rnd.nextInt(b.max_x - b.min_x) + b.min_x;
int y = rnd.nextInt(b.max_y - b.min_y) + b.min_y;
@ -220,7 +216,7 @@ public class GridFactory {
tempgrid[y][x] = c;
x = move_x(x, direction);
y = move_y(y, direction);
}
return tempgrid;
}

View File

@ -1,3 +0,0 @@
<div id="footer">
Generated at: https://bombadil.mafoo.org.uk/wordsearch/
</div>

0
war/WEB-INF/lib/commons-lang.jar Executable file → Normal file
View File

0
war/WEB-INF/lib/json-simple-1.1.1.jar Executable file → Normal file
View File

View File

@ -10,20 +10,4 @@
Wordsearch building app
</description>
<context-param>
<param-name>sqlite_db</param-name>
<param-value>/tmp/wordsearch.db</param-value>
</context-param>
<security-constraint>
<web-resource-collection>
<web-resource-name>dump</web-resource-name>
<url-pattern>/dump.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
</web-app>
</web-app>

View File

@ -3,7 +3,6 @@
<head>
<title>Wordsearch Builder: About</title>
<link rel="stylesheet" type="text/css" href="base.css" />
<link href="https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500&family=Roboto:wght@500&display=swap" rel="stylesheet">
</head>
<body>

0
war/api.jsp Executable file → Normal file
View File

20
war/base.css Executable file → Normal file
View File

@ -1,5 +1,5 @@
body {
font-family: 'Roboto', sans-serif;
body {
font-family: sans-serif;
}
.tooltip {
@ -14,16 +14,17 @@ table, th, td {
}
table#grid td {
font-family: 'Fira Mono', monospace;
font-size: 14pt;
font-family: monospace;
font-size: 22px;
}
#wrapper {
align-content: center;
width: 80%;
margin: 0 auto 60px auto;
}
#wordsearch {
float: left;
margin-bottom: 24px;
}
#words {
@ -34,11 +35,8 @@ table#grid td {
#footer {
position:absolute;
bottom:0;
}
textarea#textarea_words {
font-family: 'Fira Mono', monospace;
font-size: 10pt;
width:100%;
height:60px; /* Height of the footer */
}
@media only print {

View File

@ -3,15 +3,11 @@
<head>
<title>Wordsearch builder</title>
<link rel="stylesheet" type="text/css" href="base.css" />
<link href="https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500&family=Roboto:wght@500&display=swap" rel="stylesheet">
</head>
<%@ page import="uk.org.mafoo.wordsearch.*" %>
<%@ page import="java.util.*" %>
<%@ page import="org.apache.commons.lang.StringUtils" %>
<%@ page import="org.apache.commons.lang.StringEscapeUtils" %>
<%@ page import="java.sql.*" %>
<%@ page import="org.sqlite.*" %>
<%@ page errorPage="error.jsp" %>
<%
@ -25,55 +21,24 @@
List<String> words = new ArrayList<String>();
for ( String line : request.getParameter("words").split("\r\n")) {
words.add(line.trim().toLowerCase());
words.add(line.trim());
}
Collections.sort(words);
Collections.sort(words);
Connection conn = DriverManager.getConnection(
"jdbc:sqlite:" + getServletContext().getRealPath("/WEB-INF/files/database.sqlite"));
PreparedStatement stmt = conn.prepareStatement(
"INSERT INTO grids (remotehost, input, size_x, size_y, simple) VALUES (?, ?, ?, ?, ?)",
Statement.RETURN_GENERATED_KEYS);
// PreparedStatement getlastid = conn.prepareStatement("select last_insert_rowid();");
PreparedStatement stmt2 = conn.prepareStatement("UPDATE grids SET result=? WHERE id=?");
char[][] grid = GridFactory.makeGrid(words, height, width, simple);
stmt.setString(1, request.getRemoteHost());
stmt.setString(2, words.toString());
stmt.setInt(3, height);
stmt.setInt(4, width);
stmt.setBoolean(5, simple);
stmt.executeUpdate();
ResultSet record_id_rs = stmt.getGeneratedKeys();
int record_id = -1;
if(record_id_rs.next()){
record_id = record_id_rs.getInt(1);
}
// Actually generate the grid
char[][] grid = GridFactory.makeGrid(words, height, width, simple);
StringBuilder _csv = new StringBuilder();
for (char[] cs : grid) {
for(char c : cs) {
_csv.append(c);
_csv.append(",");
}
_csv.append("\r\n");
}
String csv = _csv.toString();
stmt2.setString(1, csv);
stmt2.setInt(2, record_id);
stmt2.executeUpdate();
conn.close();
String csv = "";
%>
<body>
<h1><%= name %></h1>
<div class="noprint">
[ <a href="index.jsp">Start again</a> | <a id='csvdownload' href="data:text/csv;base64,<%= Base64.getEncoder().encodeToString(csv.getBytes()) %>">Download CSV</a> ]
[ <a href="index.jsp">Start again</a> | <a id='csvdownload'>Download CSV</a> ]
</div>
<script>
var csv = '<%= csv %>';
var csvdownload = document.getElementById('csvdownload');
csvdownload.href='data:text/csv;base64,' + btoa(csv);
</script>
</div>
<div id="wrapper">
@ -82,18 +47,18 @@
<table id="grid">
<% for(char[] row : grid) { %>
<tr>
<% for(char c : row) {
<% for(char c : row) {
csv += "" + c + ',';
%>
<td class="cell"><%= c %></td>
<% } %>
</tr>
<%
<%
csv += "\\n";
}
%>
</table>
</div> <!-- end wordsearch -->
</div> <!-- end wordsearch -->
<div id="words">
<h2>Words</h2>
@ -103,7 +68,7 @@
<% } %>
</ul>
</div> <!-- end words -->
</div> <!-- end wrapper -->
</div> <!-- end wrapper -->
<br />
<br />
<%@include file="/WEB-INF/jspf/footer.jspf" %>

View File

@ -1,53 +0,0 @@
<%@ page contentType="text/html" %>
<%@ page import="java.sql.*" %>
<%@ page import="org.sqlite.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Database dump</title>
</head>
<body>
<h1>Database stats</h1>
<%
Connection conn =
DriverManager.getConnection("jdbc:sqlite:" + getServletContext().getRealPath("/WEB-INF/files/database.sqlite"));
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from sqlite_master where type='table' and name='grids';");
if(rs.next()) {
// we have a row and are probably ok
} else {
// Initialise the schema
PreparedStatement pstmt = conn.prepareStatement("CREATE TABLE grids (id integer primary key, ts timestamp default current_timestamp, remotehost varchar, input, size_x int, size_y int, simple tinyint, result varchar);");
pstmt.execute();
}
rs.close();
PreparedStatement ps_count = conn.prepareStatement("SELECT COUNT(*) FROM grids");
PreparedStatement ps_last = conn.prepareStatement("SELECT max(ts) FROM grids;");
ResultSet rs_count = ps_count.executeQuery();
ResultSet rs_last = ps_last.executeQuery();
int count = -1;
String last = "unknown";
if(rs_count.next()) {
count = rs_count.getInt(1);
}
if(rs_last.next()) {
last = rs_last.getString(1);
}
rs_count.close();
rs_last.close();
%>
<ul>
<li>Number of grids generated: <%= count %></li>
<li>Last grid generated at: <%= last %></li>
<li>Path to db: <pre><%= getServletContext().getRealPath("/WEB-INF/files/database.sqlite") %></pre></li>
</ul>
</body>
<%
conn.close();
%>
</html>

View File

@ -1,50 +0,0 @@
<%@ page contentType="text/html" %>
<%@ page import="java.sql.*" %>
<%@ page import="org.sqlite.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Database dump</title>
</head>
<body>
<table border="1">
<thead>
<th>id</th>
<th>timestamp</th>
<th>remotehost</th>
<th>input</th>
<th>size_x</th>
<th>size_y</th>
<th>simple</th>
<th>result</th>
</thead>
<tbody>
<%
Connection conn =
DriverManager.getConnection("jdbc:sqlite:" + getServletContext().getInitParameter("sqlite_db"));
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("select * from grids;");
while (rs.next()) {
out.println("<tr>");
out.println("<td>" + rs.getString("id") + "</td>");
out.println("<td>" + rs.getString("ts") + "</td>");
out.println("<td>" + rs.getString("remotehost") + "</td>");
out.println("<td><pre>" + rs.getString("input") + "</pre></td>");
out.println("<td>" + rs.getInt("size_x") + "</td>");
out.println("<td>" + rs.getInt("size_y") + "</td>");
out.println("<td>" + rs.getInt("simple") + "</td>");
out.println("<td><pre>" + rs.getString("result") + "</pre></td>");
out.println("</tr>");
}
rs.close();
conn.close();
%>
</tbody>
</table>
</body>
</html>

View File

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Environment</h1>
<ul>
<li>You are connecting from: <%= request.getRemoteHost() %> (<%= request.getRemoteAddr() %>)</li>
<li>If present your X-Forwarded-For header is: <%= request.getHeader("X-Forwarded-For") %></li>
</ul>
<h2>Header dump</h2>
<pre>
<%
for (java.util.Enumeration<String> headers = request.getHeaderNames(); headers.hasMoreElements(); ) {
String h = headers.nextElement();
%>
<%= h %>=<%= request.getHeader(h) %>
<%
}
%>
</pre>
</body>

View File

@ -3,7 +3,6 @@
<head>
<title>Wordsearch Builder</title>
<link rel="stylesheet" type="text/css" href="base.css" />
<link href="https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500&family=Roboto:wght@500&display=swap" rel="stylesheet">
</head>
<body>
<h1>Wordsearch Builder</h1>
@ -12,7 +11,7 @@
<h2>Words</h2>
<form action="build.jsp" method="post">
Name: <input type="text" size="25" name="name" value="Wordsearch"><br />
<textarea id="textarea_words" name="words" rows="10">
<textarea name="words" rows="10">
Kitchen
Lounge
Study