Skip to content

Commit 4be5f7b

Browse files
Add new build tool.
bibliogra.py requires Python 2, which is a pain to deal with. This commit adds a Go tool that compiles CensorBib from BibTeX to HTML. The tool does the bare minimum and is quite strict in the BibTeX format it expects.
1 parent d432134 commit 4be5f7b

File tree

21 files changed

+2381
-0
lines changed

21 files changed

+2381
-0
lines changed

src/decode.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"strings"
6+
)
7+
8+
type conversion struct {
9+
from string
10+
to string
11+
}
12+
13+
func decodeTitle(title string) string {
14+
for _, convert := range []conversion{
15+
{`\#`, "#"},
16+
{`--`, `–`},
17+
{"``", "“"},
18+
{"''", "”"},
19+
{"'", "’"}, // U+2019
20+
{`$\cdot$`, `·`}, // U+00B7.
21+
} {
22+
title = strings.Replace(title, convert.from, convert.to, -1)
23+
}
24+
25+
// Get rid of all curly brackets. We're displaying titles without changing
26+
// their casing.
27+
title = strings.ReplaceAll(title, "{", "")
28+
title = strings.ReplaceAll(title, "}", "")
29+
30+
return title
31+
}
32+
33+
func decodeAuthors(authors string) string {
34+
for _, convert := range []conversion{
35+
{"'", "’"},
36+
} {
37+
authors = strings.Replace(authors, convert.from, convert.to, -1)
38+
}
39+
// For simplicity, we expect authors to be formatted as "John Doe" instead
40+
// of "Doe, John".
41+
if strings.Contains(authors, ",") {
42+
log.Fatalf("author %q contains a comma", authors)
43+
}
44+
authorSlice := strings.Split(authors, " and ")
45+
return strings.Join(authorSlice, ", ")
46+
}
47+
48+
func decodeProceedings(proceedings string) string {
49+
for _, convert := range []conversion{
50+
{`\&`, "&"},
51+
} {
52+
proceedings = strings.Replace(proceedings, convert.from, convert.to, -1)
53+
}
54+
return proceedings
55+
}

src/decode_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestToString(t *testing.T) {
8+
testCases := []conversion{
9+
{
10+
from: "Title",
11+
to: "Title",
12+
},
13+
{
14+
from: "This is a {Title}",
15+
to: "This is a Title",
16+
},
17+
{
18+
from: "This is a {Title}",
19+
to: "This is a Title",
20+
},
21+
{
22+
from: `{\#h00t}: Censorship Resistant Microblogging`,
23+
to: `#h00t: Censorship Resistant Microblogging`,
24+
},
25+
{
26+
from: "``Good'' Worms and Human Rights",
27+
to: "“Good” Worms and Human Rights",
28+
},
29+
{
30+
from: "An Analysis of {China}'s ``{Great Cannon}''",
31+
to: "An Analysis of China’s “Great Cannon”",
32+
},
33+
{
34+
from: `lib$\cdot$erate, (n):`,
35+
to: `lib·erate, (n):`,
36+
},
37+
{
38+
from: "Well -- Exploring the {Great} {Firewall}'s Poisoned {DNS}",
39+
to: "Well – Exploring the Great Firewall’s Poisoned DNS",
40+
},
41+
}
42+
43+
for _, test := range testCases {
44+
to := decodeTitle(test.from)
45+
if to != test.to {
46+
t.Errorf("Expected\n%s\ngot\n%s", test.to, to)
47+
}
48+
}
49+
}
50+
51+
func TestDecodeAuthors(t *testing.T) {
52+
testCases := []conversion{
53+
{ // Multiple authors should be separated by commas.
54+
from: "John Doe and Jane Doe",
55+
to: "John Doe, Jane Doe",
56+
},
57+
{ // Single authors should remain as-is.
58+
from: "John Doe",
59+
to: "John Doe",
60+
},
61+
{ // Single-name authors should remain as-is.
62+
from: "John and Jane",
63+
to: "John, Jane",
64+
},
65+
{ // Non-ASCII characters should be unaffected.
66+
from: "Jóhn Doe",
67+
to: "Jóhn Doe",
68+
},
69+
{ // Apostrophes should be replaced with the right single quote.
70+
from: "John O'Brian",
71+
to: "John O’Brian",
72+
},
73+
}
74+
75+
for _, test := range testCases {
76+
to := decodeAuthors(test.from)
77+
if to != test.to {
78+
t.Errorf("Expected\n%s\ngot\n%s", test.to, to)
79+
}
80+
}
81+
}

src/footer.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package main
2+
3+
func footer() string {
4+
return `<div id="footer">
5+
Icons taken without modification from
6+
<a href="https://fontawesome.com/license">Font Awesome</a>.
7+
</div>
8+
9+
</body>
10+
</html>`
11+
}

src/go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module censorbib-go
2+
3+
go 1.21.3
4+
5+
require github.com/nickng/bibtex v1.3.0

src/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/nickng/bibtex v1.3.0 h1:iv0408z8Xe+FEVquJUo8eraXnhrAF0e+2/WayPcism8=
2+
github.com/nickng/bibtex v1.3.0/go.mod h1:4BJ3ka/ZjGVXcHOlkzlRonex6U17L3kW6ICEsygP2bg=

src/header.go

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"log"
6+
"text/template"
7+
"time"
8+
)
9+
10+
const headerTemplate = `
11+
<!DOCTYPE html>
12+
<html lang="en">
13+
14+
<head>
15+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
16+
<title>The Internet censorship bibliography</title>
17+
<link rel="icon" type="image/svg+xml" href="favicon.svg">
18+
<style>
19+
body {
20+
font-family: Roboto,Helvetica,sans-serif;
21+
background: #ddd;
22+
margin-left: auto;
23+
margin-right: auto;
24+
margin-top: 20px;
25+
max-width: 1000px;
26+
}
27+
li {
28+
margin-top: 1em;
29+
margin-bottom: 1em;
30+
margin-right: 1em;
31+
}
32+
h1 {
33+
font-size: 25px;
34+
color: #efefef;
35+
width: 80%;
36+
float: left;
37+
}
38+
ul {
39+
border-radius: 10px;
40+
border:1px solid #c0c0c0;
41+
background: #efefef;
42+
box-shadow: 2px 2px 5px #bbb;
43+
}
44+
a:link {
45+
color:#0b61a4;
46+
text-decoration:none;
47+
}
48+
a:visited {
49+
color:#033e6b;
50+
text-decoration:none;
51+
}
52+
a:hover {
53+
text-decoration:underline;
54+
}
55+
p {
56+
margin: 0px;
57+
}
58+
.author {
59+
color: #666;
60+
}
61+
.venue {
62+
font-style: italic;
63+
}
64+
.paper {
65+
font-weight: bold;
66+
}
67+
.other {
68+
color: #666;
69+
}
70+
#footer {
71+
text-align: center;
72+
line-height: 20px;
73+
}
74+
.icon {
75+
height: 1em;
76+
margin-right: 0.5em;
77+
}
78+
.icons {
79+
float: right;
80+
}
81+
.top-icon {
82+
height: 1em;
83+
width: 1em;
84+
position: relative;
85+
vertical-align: middle;
86+
margin-left: 1em;
87+
}
88+
.menu-item {
89+
padding-bottom: 5px;
90+
}
91+
.url {
92+
font-family: monospace;
93+
font-size: 12px;
94+
}
95+
:target {
96+
background-color: #f6ba81;
97+
}
98+
#left-header {
99+
flex: 4;
100+
background: #efefef;
101+
margin-right: 0.5em;
102+
border-radius: 10px;
103+
border: 1px solid #c0c0c0;
104+
box-shadow: 2px 2px 5px #bbb;
105+
overflow: hidden; /* For child elements to inherit rounded corners. */
106+
}
107+
#right-header {
108+
flex: 1;
109+
background: #efefef;
110+
margin-left: 0.5em;
111+
background: #333 url('assets/research-power-tools-cover.jpg') no-repeat;
112+
background-size: 100%;
113+
}
114+
.round-shadow {
115+
border-radius: 10px;
116+
border: 1px solid #c0c0c0;
117+
box-shadow: 2px 2px 5px #bbb;
118+
overflow: hidden; /* For child elements to inherit rounded corners. */
119+
}
120+
.flex-row {
121+
display: flex;
122+
}
123+
.flex-column {
124+
display: flex;
125+
flex-direction: column;
126+
}
127+
#title-box {
128+
text-align: center;
129+
background: #333 url('open-access.svg') right/25% no-repeat;
130+
}
131+
#censorbib-description {
132+
padding: 1em;
133+
flex: 5;
134+
}
135+
#censorbib-links {
136+
padding: 1em;
137+
flex: 2;
138+
font-size: 0.9em;
139+
}
140+
#book-info {
141+
text-align: center;
142+
padding: 0.5em;
143+
background: #333;
144+
color: #efefef;
145+
}
146+
#book-info > a:link {
147+
color: #d94b7b
148+
}
149+
#book-info > a:visited {
150+
color: #d94b7b
151+
}
152+
</style>
153+
</head>
154+
155+
<body>
156+
157+
<div class="flex-row">
158+
159+
<div id="left-header" class="flex-column round-shadow">
160+
161+
<div id="title-box">
162+
<h1>Selected Research Papers<br>in Internet Censorship</h1>
163+
</div>
164+
165+
<div class="flex-row">
166+
167+
<div id="censorbib-description">
168+
CensorBib is an online archive of selected research papers in the field
169+
of Internet censorship. Most papers on CensorBib approach the topic
170+
from a technical angle, by proposing designs that circumvent censorship
171+
systems, or by measuring how censorship works. The icons next to each
172+
paper make it easy to download, cite, and link to papers. If you think
173+
I missed a paper,
174+
<a href="https://nymity.ch/contact.txt">let me know</a>.
175+
You can sort papers by
176+
<a href="year.html">year</a>,
177+
<a href="year_reverse.html">reverse year</a> (default),
178+
<a href="author.html">author</a>, and
179+
<a href="author_reverse.html">reverse author</a>.
180+
Finally, the
181+
<a href="https://github.com/net4people/bbs/issues">net4people/bbs forum</a>
182+
has reading groups for many of the papers listed below.
183+
</div> <!-- censorbib-description -->
184+
185+
<div id="censorbib-links">
186+
<div class="menu-item">
187+
<img class="top-icon" src="assets/code-icon.svg" alt="source code icon">
188+
<a href="https://github.com/NullHypothesis/censorbib">CensorBib code</a>
189+
</div>
190+
<div class="menu-item">
191+
<img class="top-icon" src="assets/update-icon.svg" alt="update icon">
192+
<a href="https://github.com/NullHypothesis/censorbib/commits/master">Last update: {{.Date}}</a>
193+
</div>
194+
</div> <!-- censorbib-links -->
195+
196+
</div>
197+
198+
</div> <!-- left-header -->
199+
200+
<div id="right-header" class="round-shadow">
201+
202+
<div class="flex-column" style="height: 100%">
203+
<div style="flex: 1 1 auto">
204+
</div>
205+
206+
<div id="book-info" style="flex: 0 1 auto">
207+
Are you a researcher? If so, you may like my book
208+
<a href="http://research-power-tools.com">Research Power Tools</a>.
209+
</div>
210+
</div>
211+
212+
</div> <!-- right-header -->
213+
214+
</div>`
215+
216+
func header() string {
217+
tmpl, err := template.New("header").Parse(headerTemplate)
218+
if err != nil {
219+
log.Fatal(err)
220+
}
221+
i := struct {
222+
Date string
223+
}{
224+
Date: time.Now().UTC().Format(time.DateOnly),
225+
}
226+
buf := bytes.NewBufferString("")
227+
if err = tmpl.Execute(buf, i); err != nil {
228+
log.Fatalf("Error executing template: %v", err)
229+
}
230+
return buf.String()
231+
}

0 commit comments

Comments
 (0)