Skip to content

Commit 9e64d79

Browse files
committed
Science Commit 5.
1 parent 2021bba commit 9e64d79

139 files changed

Lines changed: 12094 additions & 56 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0">
4+
<display-name>NWE Module</display-name>
5+
<welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list>
6+
<session-config><session-timeout>30</session-timeout></session-config>
7+
<error-page><error-code>404</error-code><location>/index.jsp</location></error-page>
8+
<error-page><error-code>500</error-code><location>/index.jsp</location></error-page>
9+
</web-app>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2+
<%@ page import="java.sql.*, java.util.Properties, java.io.*" %>
3+
<!DOCTYPE html>
4+
<html lang="en">
5+
<head>
6+
<meta charset="UTF-8"/>
7+
<link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/><link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400;1,600&display=swap" rel="stylesheet"/>
8+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
9+
<title>Contacts — AE6E66™</title>
10+
<link rel="stylesheet" href="css/style.css"/>
11+
<script src="js/scroll-preserve.js"></script>
12+
<script src="js/nwe-readme-viewer.js"></script>
13+
</head>
14+
<body>
15+
<nav class="nav"><div class="nav-inner">
16+
<span class="nav-brand">AE6E66™</span>
17+
<ul class="nav-links">
18+
<li><a href="index.jsp">Overview</a></li>
19+
<li><a href="contacts.jsp" class="active">Contacts</a></li>
20+
<li><a href="sent.jsp">Sent</a></li>
21+
<li><a href="status.jsp">Status</a></li>
22+
</ul>
23+
<div class="nav-actions"><a href="crawl.jsp" class="nav-cta">Crawl</a></div>
24+
</div></nav>
25+
26+
<section class="hero" style="padding:4rem 2rem;">
27+
<div class="hero-inner">
28+
<span class="hero-tag">UK Parliament</span>
29+
<h1>Contacts</h1>
30+
<p>House of Lords + House of Commons members crawled from members.parliament.uk.</p>
31+
</div>
32+
</section>
33+
34+
<section class="section">
35+
<div class="section-inner">
36+
<%
37+
String sourceFilter = request.getParameter("source");
38+
Properties dbProps = new Properties();
39+
boolean propsLoaded = false;
40+
Connection conn = null;
41+
try {
42+
InputStream dbIn = application.getResourceAsStream("/WEB-INF/db.properties");
43+
if (dbIn != null) { dbProps.load(dbIn); dbIn.close(); propsLoaded = true; }
44+
if (!propsLoaded) {
45+
String[] tryPaths = { "/opt/tomcat/webapps/ae6e66/WEB-INF/db.properties" };
46+
for (String tp : tryPaths) { File f = new File(tp);
47+
if (f.exists()) { FileInputStream fis = new FileInputStream(f); dbProps.load(fis); fis.close(); propsLoaded = true; break; } }
48+
}
49+
Class.forName(dbProps.getProperty("db.driver", "com.mysql.cj.jdbc.Driver"));
50+
conn = DriverManager.getConnection(
51+
dbProps.getProperty("db.url", "jdbc:mysql://127.0.0.1:3306/nwe_ae6e66"),
52+
dbProps.getProperty("db.user", "root"),
53+
dbProps.getProperty("db.password", ""));
54+
55+
if (sourceFilter == null || sourceFilter.isEmpty()) {
56+
// Show sources (HOL / HOC)
57+
ResultSet rs = conn.createStatement().executeQuery(
58+
"SELECT source, COUNT(*) AS cnt FROM contacts GROUP BY source ORDER BY source");
59+
%>
60+
<h3>Browse by Chamber</h3>
61+
<div class="table-wrap">
62+
<table>
63+
<thead><tr><th>Chamber</th><th>Members</th></tr></thead>
64+
<tbody>
65+
<% while (rs.next()) { %>
66+
<tr><td><a href="contacts.jsp?source=<%= rs.getString("source") %>"><%= rs.getString("source") %></a></td><td><%= rs.getInt("cnt") %></td></tr>
67+
<% } rs.close(); %>
68+
</tbody>
69+
</table>
70+
</div>
71+
<%
72+
} else {
73+
PreparedStatement ps = conn.prepareStatement(
74+
"SELECT id, name, email, phone, ministry, source FROM contacts WHERE source=? ORDER BY name");
75+
ps.setString(1, sourceFilter);
76+
ResultSet rs = ps.executeQuery();
77+
%>
78+
<h3><%= sourceFilter %> Members</h3>
79+
<p style="margin-bottom:1rem;"><a href="contacts.jsp">← All Chambers</a></p>
80+
<div class="table-wrap">
81+
<table>
82+
<thead><tr><th>ID</th><th>Name</th><th>Email</th><th>Phone</th><th>Ministry</th></tr></thead>
83+
<tbody>
84+
<% while (rs.next()) {
85+
String email = rs.getString("email");
86+
String phone = rs.getString("phone");
87+
%>
88+
<tr>
89+
<td><%= rs.getInt("id") %></td>
90+
<td><%= rs.getString("name") != null ? rs.getString("name") : "" %></td>
91+
<td><%= email != null && !email.isEmpty() ? email : "" %></td>
92+
<td><%= phone != null && !phone.isEmpty() ? phone : "" %></td>
93+
<td><%= rs.getString("ministry") != null ? rs.getString("ministry") : "" %></td>
94+
</tr>
95+
<% } rs.close(); ps.close(); %>
96+
</tbody>
97+
</table>
98+
</div>
99+
<%
100+
}
101+
} catch (Exception e) {
102+
%>
103+
<p style="color:#ef4444;">Database error: <%= e.getMessage() != null ? e.getMessage().replace("<","&lt;") : "unknown" %></p>
104+
<p style="color:#5f7a5f;font-size:0.8rem;">Props loaded: <%= propsLoaded %></p>
105+
<%
106+
} finally {
107+
if (conn != null) try { conn.close(); } catch (Exception ignored) {}
108+
}
109+
%>
110+
</div>
111+
</section>
112+
113+
<footer class="footer"><div><span>&#169; 2026 MEARVK LLC. All rights reserved.</span></div></footer>
114+
</body>
115+
</html>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2+
<%@ page import="java.io.*" %>
3+
<!DOCTYPE html>
4+
<html lang="en">
5+
<head>
6+
<meta charset="UTF-8"/>
7+
<link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/><link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400;1,600&display=swap" rel="stylesheet"/>
8+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
9+
<title>Crawl — AE6E66™</title>
10+
<link rel="stylesheet" href="css/style.css"/>
11+
<script src="js/scroll-preserve.js"></script>
12+
<script src="js/nwe-readme-viewer.js"></script>
13+
</head>
14+
<body>
15+
<nav class="nav"><div class="nav-inner">
16+
<span class="nav-brand">AE6E66™</span>
17+
<ul class="nav-links">
18+
<li><a href="index.jsp">Overview</a></li>
19+
<li><a href="contacts.jsp">Contacts</a></li>
20+
<li><a href="sent.jsp">Sent</a></li>
21+
<li><a href="status.jsp">Status</a></li>
22+
</ul>
23+
<div class="nav-actions"><span class="nav-cta" style="opacity:0.7;cursor:default;">Crawl</span></div>
24+
</div></nav>
25+
26+
<section class="hero" style="padding:4rem 2rem;">
27+
<div class="hero-inner">
28+
<span class="hero-tag">Parliament Crawler</span>
29+
<h1>Crawl Status</h1>
30+
<p>Crawls members.parliament.uk member IDs 0–999 for contact data and portraits.</p>
31+
</div>
32+
</section>
33+
34+
<section class="section">
35+
<div class="section-inner">
36+
<%
37+
// Check last crawl date
38+
String configDir = application.getRealPath("/") != null ?
39+
new File(application.getRealPath("/")).getParent() + "/../../../configuration" :
40+
"/home/mearvk/IdeaProjects/Java.Web.Server.Telnet.Front.Java.21/modules/AE6E66/configuration";
41+
File lastCrawlFile = new File(configDir, ".last-crawl");
42+
String lastCrawl = "Never";
43+
boolean crawlNeeded = true;
44+
if (lastCrawlFile.exists()) {
45+
BufferedReader br = new BufferedReader(new FileReader(lastCrawlFile));
46+
lastCrawl = br.readLine();
47+
br.close();
48+
if (lastCrawl != null && !lastCrawl.isEmpty()) {
49+
try {
50+
long crawlTime = java.text.DateFormat.getDateInstance().parse(lastCrawl).getTime();
51+
crawlNeeded = (System.currentTimeMillis() - crawlTime) > 30L * 24 * 60 * 60 * 1000;
52+
} catch (Exception ignored) {}
53+
}
54+
}
55+
%>
56+
<div class="table-wrap">
57+
<table>
58+
<thead><tr><th>Property</th><th>Value</th></tr></thead>
59+
<tbody>
60+
<tr><td>Last Crawl</td><td><%= lastCrawl %></td></tr>
61+
<tr><td>Crawl Needed</td><td style="color:<%= crawlNeeded ? "#ef4444" : "#22c55e" %>;"><%= crawlNeeded ? "Yes (>30 days)" : "No (within 30 days)" %></td></tr>
62+
<tr><td>Target</td><td><code>members.parliament.uk/member/{0..999}/contact</code></td></tr>
63+
<tr><td>Policy</td><td>Skip if .last-crawl &lt; 30 days old</td></tr>
64+
<tr><td>Force Re-crawl</td><td><code>rm modules/AE6E66/configuration/.last-crawl</code></td></tr>
65+
</tbody>
66+
</table>
67+
</div>
68+
<div style="margin-top:2rem;">
69+
<p style="font-size:0.85rem;color:var(--text-muted);">To trigger a crawl, run on the server:</p>
70+
<pre style="background:var(--bg-card);padding:1rem;border-radius:8px;margin-top:0.5rem;font-size:0.8rem;color:var(--text-secondary);overflow-x:auto;">java -cp modules/AE6E66/source source.AE6E66Main</pre>
71+
</div>
72+
</div>
73+
</section>
74+
75+
<footer class="footer"><div><span>&#169; 2026 MEARVK LLC. All rights reserved.</span></div></footer>
76+
</body>
77+
</html>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
:root {
2+
--bg-dark: #0a0f0a;
3+
--bg-section: #0f1a0f;
4+
--bg-card: #142814;
5+
--text-primary: #ffffff;
6+
--text-secondary: #a1b5a1;
7+
--text-muted: #5f7a5f;
8+
--accent: #22c55e;
9+
--accent-hover: #16a34a;
10+
--border: #1e3a1e;
11+
--font: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
12+
}
13+
* { margin:0; padding:0; box-sizing:border-box; }
14+
body { font-family:var(--font); background:var(--bg-dark); color:var(--text-secondary); line-height:1.6; -webkit-font-smoothing:antialiased; }
15+
a { color:var(--accent); text-decoration:none; transition:color 0.2s; }
16+
a:hover { color:var(--accent-hover); }
17+
.nav { position:sticky; top:0; z-index:100; background:rgba(10,15,10,0.92); backdrop-filter:blur(12px); border-bottom:1px solid var(--border); }
18+
.nav-inner { max-width:1200px; margin:0 auto; padding:0 2rem; height:64px; display:flex; align-items:center; justify-content:center; gap:2rem; flex-wrap:wrap; }
19+
.nav-brand { font-size:1.125rem; font-weight:700; color:var(--text-primary); letter-spacing:-0.02em; }
20+
.nav-links { list-style:none; display:flex; gap:1.5rem; }
21+
.nav-links a { font-size:0.875rem; color:var(--text-secondary); }
22+
.nav-links a.active, .nav-links a:hover { color:var(--accent); }
23+
.nav-actions { display:flex; gap:0.75rem; }
24+
.nav-cta { font-size:0.8rem; padding:0.4rem 0.9rem; border:1px solid var(--border); border-radius:6px; color:var(--text-secondary); transition:all 0.2s; }
25+
.nav-cta:hover { border-color:var(--accent); color:var(--accent); }
26+
.hero { padding:6rem 2rem; text-align:center; }
27+
.hero-inner { max-width:800px; margin:0 auto; }
28+
.hero-tag { font-size:0.75rem; text-transform:uppercase; letter-spacing:0.05em; color:var(--accent); font-weight:600; }
29+
.hero h1 { font-size:clamp(2.5rem,5vw,3.75rem); font-weight:800; color:var(--text-primary); margin:0.5rem 0; letter-spacing:-0.03em; }
30+
.hero p { font-size:1.1rem; color:var(--text-secondary); max-width:600px; margin:0 auto; }
31+
.section { padding:5rem 2rem; border-top:1px solid var(--border); }
32+
.section-inner { max-width:1200px; margin:0 auto; }
33+
.section-inner h2 { font-size:1.75rem; font-weight:700; color:var(--text-primary); margin-bottom:1rem; }
34+
.table-wrap { overflow-x:auto; border:1px solid var(--border); border-radius:8px; }
35+
table { width:100%; border-collapse:collapse; font-size:0.875rem; }
36+
thead { background:var(--bg-card); }
37+
th { padding:0.75rem 1rem; text-align:left; font-size:0.75rem; text-transform:uppercase; letter-spacing:0.05em; color:var(--text-muted); font-weight:600; }
38+
td { padding:0.6rem 1rem; border-top:1px solid var(--border); color:var(--text-secondary); }
39+
tr:hover { background:rgba(34,197,94,0.04); }
40+
.footer { padding:3rem 2rem; border-top:1px solid var(--border); text-align:center; }
41+
.footer span { font-size:0.8rem; color:var(--text-muted); }
42+
.tabs { display:flex; gap:0.5rem; margin-bottom:1.5rem; flex-wrap:wrap; }
43+
.tab { padding:0.5rem 1rem; border:1px solid var(--border); border-radius:6px; font-size:0.8rem; color:var(--text-secondary); }
44+
.tab.active, .tab:hover { border-color:var(--accent); color:var(--accent); }
45+
code { background:var(--bg-card); padding:0.15rem 0.4rem; border-radius:4px; font-size:0.85em; }
948 KB
Loading

0 commit comments

Comments
 (0)