Initial Commit

This commit is contained in:
Sarah Jamie Lewis 2019-11-10 21:38:51 -08:00
commit ddb78fe62a
11 changed files with 329 additions and 0 deletions

247
cmd/kdb.go Normal file
View File

@ -0,0 +1,247 @@
package main
import (
"errors"
"fmt"
"html/template"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strings"
)
type Page struct {
Title string
Body template.HTML
BodyOrig string
Concept template.HTML
}
var templates = template.Must(template.ParseFiles("templates/edit.html", "templates/view.html"))
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
err := templates.ExecuteTemplate(w, tmpl+".html", p)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func (p *Page) save() error {
filename := path.Join("data", p.Title+".kdb")
return ioutil.WriteFile(filename, []byte(p.Body), 0600)
}
var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9\\-]+)(/?)$")
func getTitle(w http.ResponseWriter, r *http.Request) (string, error) {
m := validPath.FindStringSubmatch(r.URL.Path)
if m == nil {
http.NotFound(w, r)
return "", errors.New("Invalid Page Title")
}
return m[2], nil // The title is the second subexpression.
}
func hasPage(word string) bool {
if _, err := os.Stat(path.Join("data/", normalize(word)+".kdb")); err != nil {
return false
}
return true
}
func loadPage(title string) (*Page, error) {
filename := title + ".kdb"
bodyb, err := ioutil.ReadFile(path.Join("data", filename))
if err != nil {
return nil, err
}
body := template.HTMLEscapeString(string(bodyb))
concept := template.HTML(construct_graph(title))
for _, word := range strings.Fields(body) {
if hasPage(word) {
body = strings.ReplaceAll(body, word, fmt.Sprintf("<a href='/view/%v/'>%v</a>", normalize(word), normalize(word)))
}
if strings.HasPrefix(word, "http") {
body = strings.ReplaceAll(body, word, fmt.Sprintf("<a href='%v'>%v</a>", word, word))
}
if strings.HasPrefix(word, "data:image/png;base64,") {
body = strings.ReplaceAll(body, word, fmt.Sprintf("<img width=200px height=200px src='%v'/>", word))
}
}
return &Page{Title: title, Body: template.HTML(body), BodyOrig: string(bodyb), Concept: concept}, nil
}
func normalize(word string) string {
if strings.HasPrefix(word, "typeof:") {
word = word[7:]
} else if strings.HasPrefix(word, "subtype:") {
word = word[8:]
} else if strings.HasPrefix(word, "instance:") {
word = word[9:]
}
word = strings.TrimSpace(word)
return word
}
func viewHandler(w http.ResponseWriter, r *http.Request) {
title, err := getTitle(w, r)
if err != nil {
return
}
p, err := loadPage(title)
if err != nil {
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
return
}
renderTemplate(w, "view", p)
}
func editHandler(w http.ResponseWriter, r *http.Request) {
title, err := getTitle(w, r)
if err != nil {
return
}
p, err := loadPage(title)
if err != nil {
p = &Page{Title: title}
}
renderTemplate(w, "edit", p)
}
func saveHandler(w http.ResponseWriter, r *http.Request) {
title, err := getTitle(w, r)
if err != nil {
return
}
body := r.FormValue("body")
p := &Page{Title: title, Body: template.HTML(body)}
err = p.save()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/view/"+title, http.StatusFound)
}
func get_links(name string) (links []string) {
filename := name + ".kdb"
bodyb, err := ioutil.ReadFile(path.Join("data", filename))
if err != nil {
return []string{}
}
body := template.HTMLEscapeString(string(bodyb))
for _, word := range strings.Fields(body) {
if hasPage(word) {
links = append(links, word)
}
}
return
}
func construct_graph(word string) string {
seen := make(map[string]bool)
graph := "digraph {\n\""+word+"\";\n"
graph = construct_graph_sub(graph, word, seen, 1)
graph += "}"
ioutil.WriteFile("tmp.dot", []byte(graph), 0640)
subProcess := exec.Command("dot", "-Tsvg", "-otmp.svg", "tmp.dot")
subProcess.Run()
subProcess.Wait()
data, _ := ioutil.ReadFile("tmp.svg")
return "<div class=\"conceptgraph\">"+strings.ReplaceAll(string(data), `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">`, "")+"</svg>"
}
func construct_graph_sub(graph string, word string, seen map[string]bool, depth int) string {
if depth >= 0 {
} else {
return graph
}
links := get_links(normalize(word))
if !seen[normalize(word)] {
graph += fmt.Sprintf("\"%v\" [href=\"/view/%v\"];\n", normalize(word), normalize(word))
}
seen[normalize(word)] = true
seen[word] = true
graph += "# " + word + "\n"
for _, link := range links {
if strings.HasPrefix(word, "typeof:") || strings.HasPrefix(word, "instance:") || strings.HasPrefix(word, "subtype:") {
word = normalize(word)
}
if !seen[normalize(link)] {
graph += fmt.Sprintf("\"%v\" [href=\"/view/%v\"];\n", normalize(link), normalize(link))
}
if !seen[normalize(word)+"++"+normalize(link)] || !seen[normalize(link)+"++"+normalize(word)] {
if strings.HasPrefix(link, "typeof:") {
graph += fmt.Sprintf("\"%v\" -> \"%v\" [style=dotted]\n", link[7:], word)
seen[word+"++"+link[7:]] = true
seen[link[7:]+"++"+word] = true
} else if strings.HasPrefix(link, "subtype:") {
graph += fmt.Sprintf("\"%v\" -> \"%v\" [style=dotted]\n", word, link[8:])
seen[word+"++"+link[8:]] = true
seen[link[8:]+"++"+word] = true
} else if strings.HasPrefix(link, "instance:") {
graph += fmt.Sprintf("\"%v\" -> \"%v\" [style=dotted]\n", word, link[9:])
seen[word+"++"+link[9:]] = true
seen[link[9:]+"++"+word] = true
} else {
graph += fmt.Sprintf("\"%v\" -> \"%v\"\n", word, link)
}
seen[normalize(word)+"++"+normalize(link)] = true
seen[normalize(link)+"++"+normalize(word)] = true
}
//}
if !seen[link] {
graph = construct_graph_sub(graph, link, seen, depth-1)
}
}
return graph
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
root := "./data/"
var files []string
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if path != "./data/" {
files = append(files, path[5:])
}
return nil
})
body := ""
for _, file := range files {
name := strings.ReplaceAll(file, ".kdb", "")
body += fmt.Sprintf("<a href='/view/%v'>%v</a><br/>", name, name)
}
renderTemplate(w, "view", &Page{Title: "Sigil KDB", Body: template.HTML(body), BodyOrig: ""})
}
func main() {
http.HandleFunc("/", indexHandler)
http.HandleFunc("/view/", viewHandler)
http.HandleFunc("/edit/", editHandler)
http.HandleFunc("/save/", saveHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}

5
data/consensus.kdb Normal file
View File

@ -0,0 +1,5 @@
Observations: the 2/3m threshold doesn't seem to hold in particle models because of local isolation
See also: subtype:synchronization
instance:snowflake

1
data/ideas.kdb Normal file
View File

@ -0,0 +1 @@
https://www.journals.uchicago.edu/doi/abs/10.1086/281977?journalCode=an

22
data/lightning-bugs.kdb Normal file

File diff suppressed because one or more lines are too long

3
data/lotka-volterra.kdb Normal file
View File

@ -0,0 +1,3 @@
The LotkaVolterra equations, also known as the predatorprey equations, are a pair of first-order nonlinear differential equations, frequently used to describe the dynamics of biological systems in which two species interact, one as a predator and the other as
See Also: instance:predator-prey

3
data/predator-prey.kdb Normal file
View File

@ -0,0 +1,3 @@
typeof:synchronization
See also: typeof:lotka-volterra

2
data/snowflake.kdb Normal file
View File

@ -0,0 +1,2 @@
Snowflake is a toy typeof:consensus model

6
data/synchronization.kdb Normal file
View File

@ -0,0 +1,6 @@
Adjustment of a clock or watch to show the same time as another.
* instance:lightning-bugs
* instance:predator-prey
See also: typeof:consensus

1
data/test.kdb Normal file
View File

@ -0,0 +1 @@
dfgdf

6
templates/edit.html Normal file
View File

@ -0,0 +1,6 @@
<h1>Editing {{.Title}}</h1>
<form action="/save/{{.Title}}" method="POST">
<div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body}}</textarea></div>
<div><input type="submit" value="Save"></div>
</form>

33
templates/view.html Normal file
View File

@ -0,0 +1,33 @@
<html>
<head>
<style>
body {
width:75%;
margin:100px auto;
font-family: Chilanka;
overflow: visible;
}
textarea
{
width:100%;
}
.conceptgraph {
float:right;
}
</style>
</head>
<body>
<h1>{{.Title}}</h1>
<div class=".conceptgraph">{{.Concept}}</div>
<div style="white-space:pre-line" >{{.Body}}</div>
<br/><br/><br/><br/>
<hr/>
<h1>Editing {{.Title}}</h1>
<form style="width:100%;" action="/save/{{.Title}}" method="POST">
<div ><textarea name="body" rows="20" cols="80">{{printf "%s" .BodyOrig}}</textarea></div>
<div><input type="submit" value="Save"></div>
</form>
</body>
</html>