From ddb78fe62aff2e6b958775b294990452daabdcfb Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Sun, 10 Nov 2019 21:38:51 -0800 Subject: [PATCH] Initial Commit --- cmd/kdb.go | 247 +++++++++++++++++++++++++++++++++++++++ data/consensus.kdb | 5 + data/ideas.kdb | 1 + data/lightning-bugs.kdb | 22 ++++ data/lotka-volterra.kdb | 3 + data/predator-prey.kdb | 3 + data/snowflake.kdb | 2 + data/synchronization.kdb | 6 + data/test.kdb | 1 + templates/edit.html | 6 + templates/view.html | 33 ++++++ 11 files changed, 329 insertions(+) create mode 100644 cmd/kdb.go create mode 100644 data/consensus.kdb create mode 100644 data/ideas.kdb create mode 100644 data/lightning-bugs.kdb create mode 100644 data/lotka-volterra.kdb create mode 100644 data/predator-prey.kdb create mode 100644 data/snowflake.kdb create mode 100644 data/synchronization.kdb create mode 100644 data/test.kdb create mode 100644 templates/edit.html create mode 100644 templates/view.html diff --git a/cmd/kdb.go b/cmd/kdb.go new file mode 100644 index 0000000..de974fb --- /dev/null +++ b/cmd/kdb.go @@ -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("%v", normalize(word), normalize(word))) + } + if strings.HasPrefix(word, "http") { + body = strings.ReplaceAll(body, word, fmt.Sprintf("%v", word, word)) + } + if strings.HasPrefix(word, "data:image/png;base64,") { + body = strings.ReplaceAll(body, word, fmt.Sprintf("", 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 "
"+strings.ReplaceAll(string(data), ` +`, "")+"" +} + +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("%v
", 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)) +} diff --git a/data/consensus.kdb b/data/consensus.kdb new file mode 100644 index 0000000..77dfcf5 --- /dev/null +++ b/data/consensus.kdb @@ -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 diff --git a/data/ideas.kdb b/data/ideas.kdb new file mode 100644 index 0000000..8f52c4e --- /dev/null +++ b/data/ideas.kdb @@ -0,0 +1 @@ +https://www.journals.uchicago.edu/doi/abs/10.1086/281977?journalCode=an \ No newline at end of file diff --git a/data/lightning-bugs.kdb b/data/lightning-bugs.kdb new file mode 100644 index 0000000..597739b --- /dev/null +++ b/data/lightning-bugs.kdb @@ -0,0 +1,22 @@ +Lightning Bug +category: typeof:synchronization + +- + +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA4QAAAOEAgMAAACEIBeoAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEUAAAAAHwD//wD///++bF5DAAAAAWJLR0QDEQxM8gAAAAd0SU1FB+MLCgglHLaIz+kAAA5lSURBVHja7Z1LduO6DkVv3lrVqb4mkVHcIaShzKeGcps1zJfYjq0PPyAJkDjUOY1aKVuWsGmDAEFS+uefjJbcAar69W/Xy5EQiLBXy63f//RtMhJOQ5gyaOqrk3Dmqwf09iE8sNgP72cWn5+EVyP01LMH1RznSDhclYQFH1tqP6imqqBCQnzCnP5mgN9rThpsnfIm+99/Z3tIeEXCp4yT4519Y7I2EiISHhzj95+mjzd90CjfIiE4YSmPusxzJhJiE2oXc/On6l1rIyEmYVUaUZV2jxIJ8QkpypXePpbPD8Pzj58qIyE+4TwaPjwg4WjCAncaMYehIBLiE97Vrfw8bP0FCfEu5NKmm5+v/b2dhK4JKwtte2bXC3RIiE/YR/M3AQmNdPMltWt7rGiQEIRwzIW/kpJHXhJuwa1V0YRJmNmQEJ9QQwEr1/4BwLKgSEJswpAztG6kKXcwywEqCWEI7YLK07iiS+h/aSTEJ9wJenKChBchpKixGuNjoeQG/ZYuJNS2xNe0axvbfi8iCechRBNncvDVh9AsrqyRv7uLhH4Il8LXC+wzl6yVSYhPqGs3bKQiIQih3IWGhalGxyMhPiG4fHcBJNQjvJcADm6WqXEkfePw2fHlEhLiE1LU5ZXp0OtWLZRehYRzECr26S9bn0ElEl26ZvMkxCdMXXWyERoJqUH6234K57oioUaac/TP4zkbIpCCeSREJqz/sM96hKYHktALoZ7CuU7ZLVl9thoJBxKO3z5uncSTEJ9wr4anStTe31/axEoNQUJ8Qgvp155Xwes9+xcSDiH88sDaNpDOSQwWCfEJVWCqjpQpHjl0OxgS4hNatAWqSDhEiW5d6bduit22TIGEIITCg7YN0fOplhvVP6CIhIiEDSa6jAcknJFQGxtEJLyM5l8ZRsKRQu7o94p1GSTEUVG332+yYZRVJMQk3Hw+0tFrzzr07gJIiE/YW023VDvce93n8zlJOIhQdbh4KJP5cEsS4hO2BAyV1okYUF/5JuEchEWWRQ5O+5jeN7CVvIxCQnzCmE4uIe3uy7MZmyYg4QSE+9/xuAkMacOVb+giIQBhidEaabH6ODUbD0iITyg6xa9PZbOqZVKMISEA4Xde0n2ytuvDJ0iIT/hQAlLMLyxwvH0MqamREJ+whETr5N29kYT4hCmlPCftfgajSpOKBgndEq5x38t2/Rj3eyMhPmFAopixCFuh6DASkrCzGoPE6eODZmZIODWhkn7AfC5bIyEJN6rwarAQRUIx4fxbDUl4ETWU5IQtOLqTIKFvwhrrfSzOJuH8hI6sfDihdqpNQnjCIvdzcx8BEl6LEFWhAtxcXwAJBdKMIvLBpyTz/quUoJMQn7DS+hzMomjc61SmfQwJnRJmnVD18RVaKuEkIRBhixHFn00+BtgqAJAQn7ACQALWYO57YzpV0O4kxCccJVdLwEkITNg0zdY28uy0vIaEEIQBO54xoDoYuHpsLAnxCTvL0SQfCd0RIs9myLIfEnqWMIOtcQCAMRgJpyKMMrfnHJEzhB+PrdlqueychDiE2ys1pBR68ebzo/kUe5EQn7CDlk0T7FbAZL0uv13cRzZGwm6ExYHBov0UzhnvTUiISrj7vyClWCrTjnHbXEmIT2iluoZAKhCTcCChbgw4nc269iE4PwnxCXXEORZ8+SXUsWzT6S+R10lIQiWZVUGsUJ8GSxN9EuITWkIG9cxIOnosCfEJfahuQS3SPWRJmCIsTmKqHv6nL/k4kIT4hNqqjy5+h5QkdEWovkrALiJV+iEJMQllh2o5if5Nq/P2kxCfMDwSO3T6ZTHAWWQjIT7hXfLOF3V5NwnxCQ/ysJXatilJiETosmdXFQkvqMOQr+0WLQrS75BI6JWwT6YyMh8iIdJVdJRIer48c0eyH1vCzOmREJ9wo05ZUad7zZJwTsJyzbd/hoTONHCb4u3S9m5PQpeEmgmxQVeuUPgjIT6hUImkWe6cEnNLkdSW25IQlPDhV8vplZheR5a59ybR6TuGJCE+4U7vJ7u7DA5LMvXGyEdCv4SSROR2zFr0kVYAxSViJMQn1FIIu8H1a53csBhHQs+EtbcW6qX24QUJRytKmLc7+pteTn80PVhIVRsHJiE+4VlqNY9Ml53KV2rHh7LoQkJYwlXwCrZISAX07RXiZoJ8dAEJ8QktNP+qdBLG1OcH3XOJw5r5PwnxCIu1reGe7Ug+l1pH5ssTSYhP6E2HOZUJRcJSNaZO24eyHOVkrwIJXRFOeIvJQ9uREFDQyUD2+4D/wkg4mLA4xjiJjSTEIBT3vx7u+bI3WNisJMQnHC8YQ0nomtAk332ArWnCTntuSQhJKIkN6+kPIZWLYR4J8QnttHrch0DCeQjXyN/ziIS4cn5DFhKScCuLXETcfIAPvSbhCMKQysNGNKdJMGDdOpSExoTNla8aX83m4prJOgkhCL9+7tmedxW9GGuO4+u95zxIiE+orHtSkk5NKu6OkfDn3iMBEuITmmmuQgkJk5InGaEjEVaTkRCfsEr0cnzNRzhyUUufdYokxCekqAupJcxI8qfxBRES9iX0nri0T+aRcLRMCXPw7308vvU7ICEw4U8dNllaPfbdY5a9Vg4JSIhPqKn5R3ck7K/D/j0T7xq7kpuE8IRbtwlmDLFB2ungB4Youbm3Y7I1z9ddcweQcFbCfvr1r79AQkKvhMirT2TjQxJ6Vrda2XGQVuNg21DRkEgZVU9IiEloVT7wU4YmIQCh7sjw9x+Jh/TNnkmIT/hSwOW0THnElWRrrvbOSUJ8QhOZGe3mthokxCfMciZd3cGkGglBCN8+WgNJNNHZx49h0YKE3ggzqbZ0y+tBlmXfUm8kITqh3wiTc0Kp5STEJ7RU2dSIxOKl+QwkvChhbebRfmPWXl8aCf0TVljw5YFIc8wkxCPUGnf6W49FwnkID6hy4CeS0eBwFbxCwqsRqqpyXsEVAwkdEhafPZ/HaOXKSuchIQah3SDSQy2MhF7PPOjyrzz7xxvNMu9v47N9BAnxCa20xl//eeu94uMpdd5MTkJ8wmHPTrtdt8tdOUiIT5hHLR4oJqLO9q3u8YOELgi7lnSHODAJ8QlLNfs2dBJ2lZtC8lL1FglJqHcZbZ2iVzw9IiE+oVTZPGNzwPh7FZPwmoQhbX24V2retzsgIT4hRV1NujHG42pIEtYTzt//knAOSUeJbbXarPeXdQ/fxizJd0k4FSHGVEFOye+JhBByU/ulKGDNn12RcKAeQztpyJGRZPczJC+nXJUm4TjC+ZMAEl5S6+mPWi1N6b7dUIGEgISKxeNwUAnYel92sHTqJkiIQOhoEmNPG8y8EtjRBZEkRCcMdbvmzLeLbm3V71ReXCTEJ+wJVmpQhW3p85AQn9BSjutoJLwo4YtHtHlG33nMH3FBQmTC+Klt+vH+EY6Ebgnnrx2TEEpnGJ2nqvgRCfEJeygcOZSz86F9Bwm1CaPZxjSDOhJSUUXCTL7hhPcSemrETkgSjiGUBJDjMfk93p+VzWMhEuIT2hX9Y77RvcpCQhI6UqTtSAgkD0toliojkAYDJHRFOFW9mITUj+ZvFBI6MEhgok3PbpR4kRCfsMWIxJKa0vtxxNOgzrkOCT0QKjfJ3jLrRWcP41fJQSQEJtSW3oOrs6PKQdkSCfEJKcq5NilO1kk2B9RErEGFYBKOJJy/5yUhln59Fv+IB20wqO1OSIhP6FgTIpFQS3E3e/sMvNWYjkikHb1IiE+408bohiDxNLHo8YFJsHet4h0J8Qk1JGuaNflf3yLhEEIP68hqbZCVoUkITKg79it5uGAvkRCf0A6mVs80aPSAmISDCRMJhH7LGfpePMCQEJ/Q+sOKKhphkvBihAbM+aWHD926iQE1CxLiExbJu30kJGGhvEQmErolXKMvWl64IR0vXk1OQnxCgdRQe6bRJJyJcHTRLqP9TTar2pqE+IRK167T0+LaTt90IoSE+ISqijrYrZuYYfBBwvYThc6r8Cs/hKJnTtOyekZn4y8J/RJ60AzdBglHXak0R6n3B70t3yScnVBP56BSFWb+Fr5OQhIWU9lpjN+SEJ/QDz8Jr0i4iN96Fci6jdlU6tckdEnYa0h2cD8rbwyUj0mIT7hTmc/46ffllpAQn7BOokBUa4SDMS4JZyC0ACvVuBkLEnogDCc9Bktthk3LkBCf0BrMmUjoWLW9bZnzrLnPGmYwJMQntOFv/Wy/S5AQn9BaKkHINScJNQnFvX944Ocjeybh5IR1KgOzS981dkGQcFbCIPBiCjNWJPQmDCtJODVhLmFNRQIMeBLiExqoKv+Oz8Otj2QldtrwGhrT1ichPmHZlYTVB3FWvZz+IOEFCP2s7rISCa+ne4tkdrModAN7D+9Z5iOha8J0139/V9b7e60dkxCNsCV5db/ylYSTEI7SWttArie6STiIsF+lIJEhme4ZI6ELwiG5xRI0pdqkdEOTEJ8wJZjwUv09kdCPoJ7u1L9ZSQhFuIwuLphfnYSYhOGT+ooTbbe7IqEH2d2ybMspz24NB40/ybraF0BCCMLKqoZ2t17iaYUtSEJ8Qm+BgYQkpKhZVRhRAGd/SYhIWJOyJKJOy7ZASWx4HFOSGJEQlND8EaoqapnEJqEPWS7JFsG35fGLxklIeGVCkV6B4eYwJrb+uOKYgSIJuxMmLHh+XtdKiVmFVwztP3wGFRLiEypdQyrroWNBik9CMMJXsqIZYTztWiQhPmFUBRWEBr18ftsofR6oRkJ8wpvq6xoo02AkxCesUjBUWLjWsGdYkrArYTbJLsrCje4+ebehMnEnIT7ht3JZ8th+/9xq5cNXEuITirVWvfUtxQJxeB1t7umVJJyHEGF+q00kpChKX5tsxp3v1deU38NnISEooRP9/tPA436lGgnnIJTr2RAQs3ckVCD8P5utZ8Y4/EipAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE5LTExLTEwVDE2OjM3OjI4LTA4OjAwxcKsaQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOS0xMS0xMFQxNjozNzoyOC0wODowMLSfFNUAAAAASUVORK5CYII= + + I needed to use k-nearest-neighbours / quadtree based approach to get this to work. + +There are multiple approaches to the sync, from sutble adjustments to complete resets. + +source: Original Model: https://sci-hub.se/https://science.sciencemag.org/content/71/1847/537.2 +Richmond, Carl A. "Fireflies flashing in unison." Science 71.1847 (1930): 537-538. + +source: Almost there: https://sci-hub.se/https://www.nature.com/articles/096411a0 + +source: http://fiumsa.edu.bo/docentes/mramirez/RAMIREZ18%20%282%29.pdf +source: https://sci-hub.se/https://dl.acm.org/citation.cfm?id=965421&dl=ACM&coll=DL (Most useful, but doesn't cite things properly) +source: https://sci-hub.se/https://www.jstor.org/stable/24950352 + +Wrong Explanations: +http://people.math.gatech.edu/~weiss/uploads/5/8/6/1/58618765/buck_synchronous_rhythmic_flashing_of_fireflies.pdf diff --git a/data/lotka-volterra.kdb b/data/lotka-volterra.kdb new file mode 100644 index 0000000..ca19bc8 --- /dev/null +++ b/data/lotka-volterra.kdb @@ -0,0 +1,3 @@ +The Lotka–Volterra equations, also known as the predator–prey 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 \ No newline at end of file diff --git a/data/predator-prey.kdb b/data/predator-prey.kdb new file mode 100644 index 0000000..3d272ce --- /dev/null +++ b/data/predator-prey.kdb @@ -0,0 +1,3 @@ +typeof:synchronization + +See also: typeof:lotka-volterra \ No newline at end of file diff --git a/data/snowflake.kdb b/data/snowflake.kdb new file mode 100644 index 0000000..d415afe --- /dev/null +++ b/data/snowflake.kdb @@ -0,0 +1,2 @@ +Snowflake is a toy typeof:consensus model + diff --git a/data/synchronization.kdb b/data/synchronization.kdb new file mode 100644 index 0000000..7db1a3a --- /dev/null +++ b/data/synchronization.kdb @@ -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 \ No newline at end of file diff --git a/data/test.kdb b/data/test.kdb new file mode 100644 index 0000000..f81d684 --- /dev/null +++ b/data/test.kdb @@ -0,0 +1 @@ +dfgdf \ No newline at end of file diff --git a/templates/edit.html b/templates/edit.html new file mode 100644 index 0000000..61fc30b --- /dev/null +++ b/templates/edit.html @@ -0,0 +1,6 @@ +

Editing {{.Title}}

+ +
+
+
+
\ No newline at end of file diff --git a/templates/view.html b/templates/view.html new file mode 100644 index 0000000..4a11985 --- /dev/null +++ b/templates/view.html @@ -0,0 +1,33 @@ + + + + + +

{{.Title}}

+
{{.Concept}}
+
{{.Body}}
+



+
+

Editing {{.Title}}

+ +
+
+
+
+ + \ No newline at end of file