hlfw.ca

webbing

Download patch

ref: 55083db3aeac43972ea5864ef92dd4e59fe48799
parent: 43aaf43179c20ec5f99ea0e4e1f4031796368f70
author: halfwit <michaelmisch1985@gmail.com>
date: Sat Mar 28 07:47:21 PDT 2020

Move things to our internal structure

--- a/design/creatingpages
+++ /dev/null
@@ -1,107 +1,0 @@
-Starting from html, a page is translated into a template. A template is the html with the header/footer removed. Example:
-
-```
-<div class="content">
-	<main>
-		<section>
-			<h1>Something</h1>
-			<p>Content</p>
-		</section>
-	</main>
-	<aside>
-		<h2>Something else</h2>
-		<p>Content</p>
-	</aside>
-</div>
-```
-
-Then, each `string` is taken out so that it can be ran through the internationalization stuff
-
-```
-<div class="content">
-	<main>
-		<section>
-			<h1>{{.mainHeader}}</h1>
-			<p>{{.mainContent}}</p>
-		</section>
-	</main>
-	<aside>
-		<h2>{{.otherHeader}}</h2>
-		<p>{{.otherContent}}</p>
-	</aside>
-</div>
-```
-
-The {{.foo}} corresponds to the contents of pages/path/to/this/page.go. A map[string]interface{} is used, with an entry for each key above, and the value.
-
-```
-import (
-	"golang.org/x/text/message"
-)
-
-func Mypage(p *message.Printer) map[string]interface{} {
-	return map[string]interface{} {
-		"mainHeader": p.Sprint("Something"),
-		"mainContent": p.Sprint("Content"),
-		"otherHeader": p.Sprint(Something else"),
-		"otherContent: p.Sprint("Content"),
-	}
-}
-```
-
-Now, the program when it starts up will run the init() function ofanything imported. In client.go, you would import the library that this page you've made belongs to as an empty import - this basically means it'll always run the init(). We use this to our advantage
-
-```
-func init() {
-	b := &router.Page{
-		// Who can access the page
-		Access: router.GuestAuth|router.PatientAuth, // or router.DoctorAuth
-		// There's a basic CSS for every given page that is already applied
-		// we use this if we want special css for this page
-		Css: "customstuffforonlythispage.css",
-		// would relate to, for example, olmaxmedical.com/path/to/this/page.html
-		Path: path/to/this/page 
-		Data: Mypage, // pointer to function we defined above
-		// These load your interface{} item above so you can access the lists
-		// This keeps the API boundaries clean, and more importantly drastically
-		// simplifies writing more pages
-		Extra: router.ListCountries|router.ListDoctors|router.ListSpecialties, 
-}
-```
-
-An example using one of the above extras would be like so
-
-```
-<div class="content">
-	<main>
-		<section>
-			<h1>Something</h1>
-			<p>Content</p>
-		</section>
-	</main>
-	<aside>
-		<form action="dosomething">
-			<select name="Specialties">
-			{{range .specialties}} <!-- this is from ListSpecialties-->
-				<option value="{{.ID}}">{{.Name}}</option>
-			{{end}}
-			</select>
-		</form>
-		<h2>Something else</h2>
-		<p>Content</p>
-	</aside>
-</div>
-```
-
-The structs for all of these are listed in their source files in router/, as they're only ever loaded and used there.
-
-So each page is basically `cached` at startup, and calling them has only the overhead of translation, which is very quick map lookups based on a numerical identifier.
-There's no further steps required; just make the two files, possibly the extra CSS, and if you are creating a new library (that is to say, a path in olmaxmedical.com/some/new/area.html) make sure it gets added in client.go
-
-```
-import (
-	...
-	_ "olmax/some/new"
-	...
-)
-```
--- a/design/routing
+++ /dev/null
@@ -1,28 +1,0 @@
-For now the router is a simple hand-made. It sends a majority of pages that aren't related to a client session via a default method: 
-
-```
-func (d *handle) normal(w http.ResponseWriter, r *http.Request) {
-	// Get the language for a given client request
-	accept := r.Header.Get("Accept-Language")
-	[...]
-	p := message.NewPrinter(tag)
-	// Get the session based on tokens
-	// If none exist, start a new one
-	us := d.manager.SessionStart(w, r)
-	[...]
-	// Check the auth for a given site, or return a 503 error
-	// Additionally, we get the data based on that identity for things like the header's links
-	// for example for someone authorized as a patient
-	// This pagedata calls the functions in pages/path/to/my/page
-	// Then adds all additional data to the map so a template can be fully Executed
-	// Then it returns a []byte with the actual HTML served to the client
-	data, _ := pagedata(p, requsted_path, loginstatus, "patient")
-	// Write the actual data to w
-	fmt.Fprintf(w, "%s", data)
-}
-```
-
- * actual code is slightly different
-
-At the present time, generic form parsing is not implemented, but the pathway will be roughly similar; a switch on r.Method will be used (one of GET, POST, etc etc) and a similarily generic function to the above will be used to get form data, pass it through a validator that lives in forms/path/to/my/page
-Which returns an array of any validation errors.
--- a/design/startup
+++ /dev/null
@@ -1,8 +1,0 @@
-the program starts up, caching all templates as structs with the function to call for page data, the various flags for additional data they want from the generic page handler, and the access flags
-
-Then, the program runs through every template and makes sure that they execute, at least using the English translations (the default ones) it'll error out and print every template error it encounters on stdout
-
-Then it spins up the (currently broken, so disabled) garbage collection. This garbage collection removes old session data, like tokens that have expired, rather than spinning up goroutines waiting to time out the token.
-We may revisit this, since a token, once used, is considered expired (and can be deleted) so it won't need garbage collection.
-
-Finally we start listening for incoming connections, using the router. It's handed a structure to use for accessing all the required session data through method calls, which keeps the sessions out of global scope
\ No newline at end of file
--- a/email/form.go
+++ /dev/null
@@ -1,83 +1,0 @@
-// All forms must set the "sendto" key to a []string{"someemail@email.com"}
-// As well, they require a "name" and "email" combo.
-
-package email
-
-import (
-	"bytes"
-	"log"
-	"mime/multipart"
-	"net/mail"
-	"net/smtp"
-	"text/template"
-
-	"github.com/scorredoira/email"
-	"golang.org/x/text/message"
-)
-
-const tmpl = `
-<!DOCTYPE html>
-<html>
-	<title>{{index .pagetitle 0}}</title>
-<head>
-	
-</head>
-<body>
-	<h2>{{index .pagetitle 0}}</h2>
-	<ul>
-	{{range $key, $value := . }}
-		{{if eq $key "pagetitle"}}
-		{{else if eq $key "country" }}
-			<li>countries: {{range $value}}{{.}} {{end}}</li>
-		{{else if eq $key "specialty" }}
-			<li>specialties: {{range $value}}{{.}} {{end}}</li>
-		{{else}}
-			{{$val := len $value}}
-			{{if eq $val 2}}
-				<li>{{$key}}: {{index $value 1 }}</li>
-			{{else}}
-				<li>{{$key}}: {{index $value 0 }}</li>
-			{{end}}
-		{{end}}
-	{{end}}
-	</ul>
-</body>
-</html>
-`
-
-var t *template.Template
-
-func init() {
-	t = template.Must(template.New("email").Parse(tmpl))
-}
-
-// SendForm - Fill in the template and send it out from our email address
-func SendForm(form map[string][]string, p *message.Printer, attachments map[string]multipart.File) {
-	var body bytes.Buffer
-	address := form["sendto"][0]
-	delete(form, "sendto")
-	if err := t.Execute(&body, form); err != nil {
-		log.Println(err)
-		return
-	}
-	m := email.NewHTMLMessage("Form contents", body.String())
-	m.From = mail.Address{
-		Name:    "From",
-		Address: "olmaxmedical@gmail.com",
-	}
-	m.AddTo(mail.Address{
-		Name:    "To",
-		Address: address,
-	})
-	for name, buff := range attachments {
-		var attc bytes.Buffer
-		attc.ReadFrom(buff)
-		if err := m.AttachBuffer(name, attc.Bytes(), false); err != nil {
-			log.Println(err)
-		}
-	}
-	auth := smtp.PlainAuth("", "olmaxmedical@gmail.com", "hunter2", "smtp.gmail.com")
-	if err := email.Send("smtp.gmail.com:587", auth, m); err != nil {
-		log.Println(err)
-	}
-}
--- a/email/reset.go
+++ /dev/null
@@ -1,61 +1,0 @@
-package email
-
-import (
-	"bytes"
-	"fmt"
-	"log"
-	"net/smtp"
-	"time"
-
-	"github.com/google/uuid"
-	"github.com/olmaxmedical/olmax_go/db"
-	"golang.org/x/text/message"
-)
-
-// SendReset - Wrapper for resetmail and timeout
-func SendReset(email string, p *message.Printer) {
-	u, _ := uuid.NewRandom()
-	token := u.String()
-	if db.UserExists(email) {
-		db.CreateTempEntry("", "", email, "", token)
-		resetemail(token, email, p)
-		go func() {
-			time.Sleep(time.Minute * 10)
-			db.RemoveTempEntry(token)
-		}()
-	}
-}
-
-// NextResetToken - Make sure we have unique tokens!
-func NextResetToken(old, user string) string {
-	if db.FindTempEntry(old) {
-		db.RemoveTempEntry(old)
-		u, _ := uuid.NewRandom()
-		token := u.String()
-		db.CreateTempEntry("", "", user, "", token)
-		go func() {
-			time.Sleep(time.Minute * 10)
-			db.RemoveTempEntry(token)
-		}()
-		return token
-	}
-	return ""
-}
-
-func resetemail(token string, sendto string, p *message.Printer) {
-	var msg bytes.Buffer
-	msg.WriteString("From: ")
-	msg.WriteString("olmaxmedical@gmail.com" + "\n")
-	msg.WriteString("To: ")
-	msg.WriteString(sendto + "\n")
-	msg.WriteString(p.Sprintf("Subject: Olmax Medical - Reset Your Password\n\n"))
-	msg.WriteString(p.Sprintf("Please click the following link to reset your password "))
-	msg.WriteString(fmt.Sprintf("%s/reset/%s\n", url, token))
-	err := smtp.SendMail("smtp.gmail.com:587",
-		smtp.PlainAuth("", "olmaxmedical@gmail.com", "hunter2", "smtp.gmail.com"),
-		"olmaxmedical@gmail.com", []string{sendto}, msg.Bytes(),
-	)
-	if err != nil {
-		log.Printf("smtp error: %v", err)
-	}
-}
--- a/email/signup.go
+++ /dev/null
@@ -1,61 +1,0 @@
-package email
-
-import (
-	"bytes"
-	"fmt"
-	"log"
-	"net/http"
-	"net/smtp"
-	"time"
-
-	"github.com/google/uuid"
-	"github.com/olmaxmedical/olmax_go/db"
-	"golang.org/x/text/message"
-)
-
-// TODO(halfwit) Update with whichever TLD we land on
-var url = "https://medical.olmax.dev"
-
-// SendSignup - email our prospective clients and create tokens
-func SendSignup(first, last, email, pass string, p *message.Printer) {
-	if !db.UserExists(email) {
-		u, _ := uuid.NewRandom()
-		token := u.String()
-		db.CreateTempEntry(first, last, email, pass, token)
-		signupemail(token, email, p)
-		go func() {
-			// Blow away the entry unconditionally after 10 minutes
-			time.Sleep(time.Minute * 10)
-			db.RemoveTempEntry(token)
-		}()
-	}
-}
-
-// ValidateSignupToken - Make sure token is good
-func ValidateSignupToken(w http.ResponseWriter, r *http.Request, token string) {
-	if db.FindTempEntry(token) {
-		db.CreateEntry(token)
-		http.Redirect(w, r, "/login.html", 302)
-		return
-	}
-	http.Error(w, "Bad Request", 400)
-
-}
-
-func signupemail(token string, sendto string, p *message.Printer) {
-	var msg bytes.Buffer
-	msg.WriteString("From: ")
-	msg.WriteString("olmaxmedical@gmail.com" + "\n")
-	msg.WriteString("To: ")
-	msg.WriteString(sendto + "\n")
-	msg.WriteString(p.Sprintf("Subject: Olmax Medical - Verify your new account\n\n"))
-	msg.WriteString(p.Sprintf("Please click the following link to finalize your account creation "))
-	msg.WriteString(fmt.Sprintf("%s/activate/%s\n", url, token))
-	err := smtp.SendMail("smtp.gmail.com:587",
-		smtp.PlainAuth("", "olmaxmedical@gmail.com", "hunter2", "smtp.gmail.com"),
-		"olmaxmedical@gmail.com", []string{sendto}, msg.Bytes(),
-	)
-	if err != nil {
-		log.Printf("smtp error: %v", err)
-	}
-}
--- a/forms/doctor/application.go
+++ /dev/null
@@ -1,66 +1,0 @@
-package forms
-
-import (
-	"fmt"
-	"net/http"
-
-	"github.com/albrow/forms"
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Form{
-		Access:    router.GuestAuth,
-		Path:      "doctor/application",
-		Validator: application,
-		Redirect:  "/index.html",
-		After:     plugins.EmailForm | plugins.Countries | plugins.Services | plugins.FormToken,
-	}
-	router.AddPost(b)
-}
-
-func application(r *http.Request, p *message.Printer) []string {
-	var errors []string
-	data, err := forms.Parse(r)
-	if err != nil {
-		errors = append(errors, "Internal server error")
-		return errors
-	}
-	val := data.Validator()
-	val.Require("gender").Message(p.Sprint("Please select a biological gender"))
-	if r.PostFormValue("gender") != "male" && r.PostFormValue("gender") != "female" {
-		val.AddError("gender", p.Sprint("Invalid selection for gender"))
-	}
-	val.RequireFile("cv").Message(p.Sprint("Empty or missing CV"))
-	val.AcceptFileExts("cv", "application/msword,applicationvnd.openxmlformats-officedocument.wordprocessingml.document,application/pdf").Message(p.Sprint("Unsupported filetype for CV"))
-	val.RequireFile("diploma").Message(p.Sprint("Empty or missing Diploma/Board Certification"))
-	val.AcceptFileExts("cv", "application/msword,applicationvnd.openxmlformats-officedocument.wordprocessingml.document,application/pdf").Message(p.Sprint("Unsupported filetype for Diploma/Board Certification"))
-	for i := 1; i < 12; i++ {
-		num := fmt.Sprintf("q%d", i)
-		sel, ok := r.Form[num]
-		if !ok {
-			val.AddError(num, p.Sprintf("No selection for question %d", i))
-			continue
-		}
-		if sel[0] == "Yes" || sel[0] == "yes" || sel[0] == "no" || sel[0] == "No" {
-			continue
-		}
-		val.AddError(num, p.Sprintf("Invalid selection for question %d", i))
-	}
-	val.Require("email").Message(p.Sprintf("Valid email required"))
-	val.MatchEmail("email").Message(p.Sprintf("Invalid email"))
-	val.Require("name").Message(p.Sprintf("Full name required"))
-	val.MinLength("name", 2).Message(p.Sprintf("Full name must be at least 2 characters"))
-	if r.PostFormValue("redFlag") != "on" {
-		val.AddError("redFlag", p.Sprint("Invalid selection for confirm element"))
-	}
-	if val.HasErrors() {
-		errors = append(errors, val.Messages()...)
-	}
-	r.Form["pagetitle"] = []string{"Application for doctor"}
-	r.Form["sendto"] = []string{"olmaxmedical@gmail.com"}
-	delete(r.Form, "redFlag")
-	return errors
-}
--- a/forms/doctor/profile.go
+++ /dev/null
@@ -1,53 +1,0 @@
-package forms
-
-import (
-	"net/http"
-	"time"
-
-	"github.com/albrow/forms"
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Form{
-		Access:    router.DoctorAuth,
-		Path:      "doctor/profile",
-		Validator: profile,
-		Redirect:  "/doctor/profile.html",
-		After:     plugins.FormToken | plugins.AddAppointment,
-	}
-	router.AddPost(b)
-}
-
-func profile(r *http.Request, p *message.Printer) []string {
-	var errors []string
-	data, err := forms.Parse(r)
-	if err != nil {
-		errors = append(errors, "Internal server error")
-		return errors
-	}
-	val := data.Validator()
-	val.Require("BTCperU").Message(p.Sprint("Please enter a rate (Bitcoin/15min)"))
-	bcu := data.GetFloat("BTCperU")
-	if 0.0 > bcu || bcu > 1.0 {
-		val.AddError("BTCperU", p.Sprint("BTC/15min rate out of range"))
-	}
-	val.Require("startDate").Message(p.Sprint("Start date required"))
-	_, err = time.Parse("2006-01-02T15:04:05", r.Form.Get("startDate"))
-	if err != nil {
-		val.AddError("startDate", p.Sprint("Invalid start-date entered"))
-	}
-
-	val.Require("endDate").Message(p.Sprint("End date required"))
-	_, err = time.Parse("2006-01-02T15:04:05", r.Form.Get("endDate"))
-	if err != nil {
-		val.AddError("endDate", p.Sprint("Invalid end-date entered"))
-	}
-
-	if val.HasErrors() {
-		errors = append(errors, val.Messages()...)
-	}
-	return errors
-}
--- a/forms/login.go
+++ /dev/null
@@ -1,39 +1,0 @@
-package forms
-
-import (
-	"net/http"
-
-	"github.com/albrow/forms"
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Form{
-		Access:    router.GuestAuth,
-		Path:      "login",
-		Validator: login,
-		After:     plugins.ValidateLogin,
-		Redirect:  "/profile.html",
-	}
-	router.AddPost(b)
-}
-
-func login(r *http.Request, p *message.Printer) []string {
-	var errors []string
-	data, err := forms.Parse(r)
-	if err != nil {
-		errors = append(errors, p.Sprint("Internal server error"))
-		return errors
-	}
-	val := data.Validator()
-	val.Require("email").Message(p.Sprint("Username required"))
-	val.MatchEmail("email").Message(p.Sprint("User name must be a valid email"))
-	val.Require("pass").Message(p.Sprint("Password required"))
-	val.MinLength("pass", 8).Message(p.Sprint("Password must be at least 8 characters"))
-	if val.HasErrors() {
-		errors = append(errors, val.Messages()...)
-	}
-	return errors
-}
--- a/forms/newpassword.go
+++ /dev/null
@@ -1,42 +1,0 @@
-package forms
-
-import (
-	"net/http"
-
-	"github.com/albrow/forms"
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Form{
-		Access:    router.GuestAuth,
-		Path:      "newpassword",
-		Validator: newPassword,
-		Redirect:  "/login.html",
-		After:     plugins.ResetPassword | plugins.FormToken,
-	}
-	router.AddPost(b)
-}
-
-func newPassword(r *http.Request, p *message.Printer) []string {
-	var errors []string
-	data, err := forms.Parse(r)
-	if err != nil {
-		errors = append(errors, "Internal server error")
-		return errors
-	}
-	val := data.Validator()
-	val.Require("password").Message(p.Sprintf("Password required"))
-	val.MinLength("password", 8).Message(p.Sprintf("Password must be at least 8 characters"))
-	val.Require("reenter").Message(p.Sprintf("Re-enter same password"))
-	val.MinLength("reenter", 8).Message(p.Sprintf("Password must be at least 8 characters"))
-	if val.HasErrors() {
-		errors = append(errors, val.Messages()...)
-	}
-	if data.Get("reenter") != data.Get("password") {
-		errors = append(errors, p.Sprint("Passwords do not match"))
-	}
-	return errors
-}
--- a/forms/patient/offer.go
+++ /dev/null
@@ -1,53 +1,0 @@
-package forms
-
-import (
-	"net/http"
-	"time"
-
-	"github.com/albrow/forms"
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Form{
-		Access:    router.PatientAuth,
-		Path:      "patient/offer",
-		Validator: offer,
-		After:     plugins.Search | plugins.Services,
-		Redirect:  "results.html",
-	}
-	router.AddPost(b)
-}
-
-func offer(r *http.Request, p *message.Printer) []string {
-	var errors []string
-	data, err := forms.Parse(r)
-	if err != nil {
-		errors = append(errors, p.Sprint("Internal server error"))
-		return errors
-	}
-	val := data.Validator()
-	val.Require("Amount").Message(p.Sprint("Please enter a target rate (Bitcoin/15min)"))
-	bcu := data.GetFloat("Amount")
-	if 0.0 > bcu || bcu > 1.0 {
-		val.AddError("Amount", p.Sprint("BTC/15min rate out of range"))
-	}
-	val.Require("startDate").Message(p.Sprint("Start date required"))
-	_, err = time.Parse("2006-01-02T15:04:05", r.Form.Get("startDate"))
-	if err != nil {
-		val.AddError("startDate", p.Sprint("Invalid start-date entered"))
-	}
-
-	val.Require("endDate").Message(p.Sprint("End date required"))
-	_, err = time.Parse("2006-01-02T15:04:05", r.Form.Get("endDate"))
-	if err != nil {
-		val.AddError("endDate", p.Sprint("Invalid end-date entered"))
-	}
-	val.Require("")
-	if val.HasErrors() {
-		errors = append(errors, val.Messages()...)
-	}
-	return errors
-}
--- a/forms/patient/profile.go
+++ /dev/null
@@ -1,35 +1,0 @@
-package forms
-
-import (
-	"net/http"
-
-	"github.com/albrow/forms"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Form{
-		Access:    router.PatientAuth,
-		Path:      "patient/profile",
-		Validator: profile,
-		After:     0,
-		Redirect:  "/patient/profile.html",
-	}
-	router.AddPost(b)
-}
-
-func profile(r *http.Request, p *message.Printer) []string {
-	var errors []string
-	data, err := forms.Parse(r)
-	if err != nil {
-		errors = append(errors, p.Sprint("Internal server error"))
-		return errors
-	}
-	val := data.Validator()
-	//
-	if val.HasErrors() {
-		errors = append(errors, val.Messages()...)
-	}
-	return errors
-}
--- a/forms/patient/symptoms.go
+++ /dev/null
@@ -1,79 +1,0 @@
-package forms
-
-import (
-	"net/http"
-	"time"
-
-	"github.com/albrow/forms"
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Form{
-		Access:    router.PatientAuth,
-		Path:      "patient/symptoms",
-		Validator: symptoms,
-		After:     plugins.EmailForm,
-		Redirect:  "patient/profile.html",
-	}
-	router.AddPost(b)
-}
-
-func symptoms(r *http.Request, p *message.Printer) []string {
-	var errors []string
-	data, err := forms.Parse(r)
-	if err != nil {
-		errors = append(errors, p.Sprint("Internal server error"))
-		return errors
-	}
-	val := data.Validator()
-	// TODO(halfwit): Date must be in a reasonable range
-	val.Require("bday").Message(p.Sprint("Birth date required"))
-	_, err = time.Parse("2006-01-02T15:04:05", r.Form.Get("bday"))
-	if err != nil {
-		val.AddError("bday", p.Sprint("Invalid birth date"))
-	}
-	val.Require("onset").Message(p.Sprint("Please enter the date and time your symptoms started"))
-	_, err = time.Parse("2006-01-02T15:04:05", r.Form.Get("onset"))
-	if err != nil {
-		val.AddError("bday", p.Sprint("Invalid date"))
-	}
-	val.Require("gender").Message(p.Sprint("Please select a biological gender"))
-	if r.PostFormValue("gender") != "male" && r.PostFormValue("gender") != "female" {
-		val.AddError("gender", p.Sprint("Invalid selection for gender"))
-	}
-	val.GreaterOrEqual("duration", 0).Message(p.Sprint("Invalid value entered for how long symptoms have lasted"))
-	val.Require("reason").Message(p.Sprint("Please provide the reason for visit"))
-	val.Require("location").Message(p.Sprint("Please list the area the symptom(s) appear"))
-	val.Require("characteristic").Message(p.Sprint("Please provide a description of your symptoms"))
-	val.Require("aggreAlevi").Message(p.Sprint("Please note anything which improves/worsens your symptoms"))
-	for _, i := range []string{
-		"feversChills",
-		"wtGainLoss",
-		"vision",
-		"lung",
-		"heart",
-		"bowel",
-		"renal",
-		"musSkel",
-		"neuro",
-		"psych",
-	} {
-		sel, ok := r.Form[i]
-		if !ok {
-			val.AddError(i, p.Sprintf("No selection for %s", i))
-			continue
-		}
-		if sel[0] == "Yes" || sel[0] == "yes" || sel[0] == "no" || sel[0] == "No" {
-			continue
-		}
-		val.AddError(i, p.Sprintf("Invalid selection for %s", i))
-	}
-	r.Form["pagetitle"] = []string{"Client symptoms"}
-	if val.HasErrors() {
-		errors = append(errors, val.Messages()...)
-	}
-	return errors
-}
--- a/forms/resetpassword.go
+++ /dev/null
@@ -1,37 +1,0 @@
-package forms
-
-import (
-	"net/http"
-
-	"github.com/albrow/forms"
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Form{
-		Access:    router.GuestAuth,
-		Path:      "resetpassword",
-		Validator: reset,
-		Redirect:  "/login.html",
-		After:     plugins.ResetPassword,
-	}
-	router.AddPost(b)
-}
-
-func reset(r *http.Request, p *message.Printer) []string {
-	var errors []string
-	data, err := forms.Parse(r)
-	if err != nil {
-		errors = append(errors, "Internal server error")
-		return errors
-	}
-	val := data.Validator()
-	val.Require("email").Message(p.Sprintf("Valid email required"))
-	val.MatchEmail("email").Message(p.Sprintf("Invalid email"))
-	if val.HasErrors() {
-		errors = append(errors, val.Messages()...)
-	}
-	return errors
-}
--- a/forms/signup.go
+++ /dev/null
@@ -1,43 +1,0 @@
-package forms
-
-import (
-	"net/http"
-
-	"github.com/albrow/forms"
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Form{
-		Access:    router.GuestAuth,
-		Path:      "signup",
-		Validator: signin,
-		Redirect:  "/login.html",
-		After:     plugins.SendSignup,
-	}
-	router.AddPost(b)
-}
-
-func signin(r *http.Request, p *message.Printer) []string {
-	var errors []string
-	data, err := forms.Parse(r)
-	if err != nil {
-		errors = append(errors, "Internal server error")
-		return errors
-	}
-	val := data.Validator()
-	val.Require("fname").Message(p.Sprintf("First name required"))
-	val.MinLength("fname", 2).Message(p.Sprintf("First name must be at least 2 characters"))
-	val.Require("lname").Message(p.Sprintf("Last name required"))
-	val.MinLength("lname", 2).Message(p.Sprintf("Last name must be at least 2 characters"))
-	val.Require("email").Message(p.Sprintf("Valid email required"))
-	val.MatchEmail("email").Message(p.Sprintf("Invalid email"))
-	val.Require("pass").Message(p.Sprintf("Password required"))
-	val.MinLength("pass", 8).Message(p.Sprintf("Password must be at least 8 characters"))
-	if val.HasErrors() {
-		errors = append(errors, val.Messages()...)
-	}
-	return errors
-}
--- a/pages/doctor/application.go
+++ /dev/null
@@ -1,53 +1,0 @@
-package doctor
-
-import (
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth,
-		CSS:    "",
-		Path:   "doctor/application",
-		Data:   application,
-		Extra:  plugins.Countries | plugins.Services | plugins.FormErrors | plugins.FormToken,
-	}
-	router.AddPage(b)
-}
-
-func application(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"fullname":   p.Sprint("Full name"),
-		"user":       p.Sprint("Personal"),
-		"email":      p.Sprint("Email"),
-		"title":      p.Sprint("Olmax Medical | Application"),
-		"offer":      p.Sprint("Create A New Offer"),
-		"area":       p.Sprint("Location and specialties"),
-		"docspecial": p.Sprint("What is your specialty, or specialties?"),
-		"gender":     p.Sprint("What is your biological gender?"),
-		"male":       p.Sprint("Male"),
-		"female":     p.Sprint("Female"),
-		"documents":  p.Sprint("Documents"),
-		"cv":         p.Sprint("Please copy and paste your CV:"),
-		"diploma":    p.Sprint("Please upload a copy of your medical school diploma and copy of your board certification:"),
-		"complete":   p.Sprint("Please complete the following"),
-		"yes":        p.Sprint("Yes"),
-		"no":         p.Sprint("No"),
-		"q1":         p.Sprint("Has your license to practive medicine in any jurisdiction, your Drug Enforcement Administration registration or any applicable narcotic registration in any jurisdiction ever been denied, limited, restricted, suspended, revoked, not renewed, or subject to probationary conditions, or have you voluntarily or involuntarily relinquished any such license or registration or voluntarily or involuntarily accepted any such actions or conditions, or have you ever been fined or received a letter of reprimand or is such action pending?"),
-		"q2":         p.Sprint("Have you ever been charged, suspended, fined, diciplined, or otherwise sanctioned, subject to probationary conditions, restricted or excluded, or have you voluntarily or involuntarily relinquished eligibility to provide services or accepted conditions on your eligibility to provide services by any form of medical insurance entity, or any public program, or is any such action pending?"),
-		"q3":         p.Sprint("Have your clinical privileges, membership, contractual participation or employment by any medical organization (e.g. hospital medical staff, medical group, independent practice association, health plan, health mantenance organization, preferred provider organization, private payer, medical society, professional association, medical school faculty position or other health delivery entity or system), ever been denied, suspended, restricted, reduced, subject to probationairy conditions, revoked or not renewed for any reason, or is any such action pending?"),
-		"q4":         p.Sprint("Have you ever voluntarily or involuntarily withdrawn a request for membership or clinical privileges, voluntarily or involuntarily relinquished membership or clinical privileges, allowed such membership or clinical privileges to expire, or resigned from any medical organization (e.g., hospital medical staff, medical group, independent practice association, health plan, health mantenance organization, preferred provider organization, private payer, medical society, professional association, medical school faculty position or other health delivery entity or system), for any reason, or in return for such an investigation not being conducted, or is any such action pending?"),
-		"q5":         p.Sprint("Have you ever terminated contractual participation or employment with any medical organization (e.g., hospital medical staff, medical group, independent practice association, health plan, health mantenance organization, preferred provider organization, private payer, medical society, professional association, medical school faculty position or other health delivery entity or system), or allowed such contract or employment to expire, for any reason, or in return for such an investigation not being conducted, or is any such action pending?"),
-		"q6":         p.Sprint("Have you ever surrendered, voluntarily withdrawn, or been requested or compelled to relinquish your status as a student in good standing in any internship, residency, fellowship, preceptorship, or other clinical education program, or is any such action pending?"),
-		"q7":         p.Sprint("Has your membership or fellowship in any local, county, state, regional, nation, or international professional organization ever been revoked, denied, reduced, limited, subject to probationary conditions, or not renewed, or is any such action pending?"),
-		"q8":         p.Sprint("Have you ever been denied certification/re-certification by a specialty board, or has your eligibility certification or re-certification status changed, or is any such action pending?"),
-		"q9":         p.Sprint("Have you ever been convicted of or pled <i>nolo contendre</i> to any crime (other than a minor traffic violation), or is any such action pending?"),
-		"q10":        p.Sprint("Do you currently use drugs illegally, or in the past five years have you participated in any treatment or diversion program related to drug use, alcohol dependency, or psychiatric problems?"),
-		"q11":        p.Sprint("Have any judgments been entered against you, or settlements been agreed to by you (including dismissals) within the last ten (10) years, in professional liability cases, or are there any filed and served professional liability lawsuits/arbitrations against you pending?"),
-		"q12":        p.Sprint("I hereby affirm that the information above and any addenda thereto is true, current, correct, and complete to the best of my knowledge and belief and is furnished in good faith, I understand that omissions or misrepresentations may result in denial of my application to participate in Olmax Medical web services."),
-		"confirm":    p.Sprint("Confirm"),
-		"submit":     p.Sprint("Submit"),
-	}
-}
--- a/pages/doctor/bookings.go
+++ /dev/null
@@ -1,25 +1,0 @@
-package doctor
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.DoctorAuth,
-		CSS:    "",
-		Path:   "doctor/bookings",
-		Data:   bookings,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func bookings(p *message.Printer) map[string]interface{} {
-	//TODO(halfwit) populate with database
-	return map[string]interface{}{
-		"title":      p.Sprintf("Olmax Medical | Bookings"),
-		"mainHeader": p.Sprintf("Available patients"),
-	}
-}
--- a/pages/doctor/findpatients.go
+++ /dev/null
@@ -1,25 +1,0 @@
-package doctor
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.DoctorAuth,
-		CSS:    "",
-		Path:   "doctor/findpatients",
-		Data:   findpatients,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func findpatients(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":      p.Sprintf("Olmax Medical | Find Patients"),
-		"mainHeader": p.Sprintf("Available patients"),
-		// more fields to populate when we have db access
-	}
-}
--- a/pages/doctor/profile.go
+++ /dev/null
@@ -1,34 +1,0 @@
-package doctor
-
-import (
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.DoctorAuth,
-		CSS:    "",
-		Path:   "doctor/profile",
-		Data:   profile,
-		Extra:  plugins.FormErrors | plugins.FormToken | plugins.ListBookings,
-	}
-	router.AddPage(b)
-}
-
-func profile(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":          p.Sprint("Olmax Medical | Profile"),
-		"greetingHeader": p.Sprint("Hello "),
-		"offer":          p.Sprint("Create New Offer"),
-		"specialty":      p.Sprint("Your specialties"),
-		"country":        p.Sprint("Your countries"),
-		"apptLegend":     p.Sprint("Appointment Times: "),
-		"from":           p.Sprint("From:"),
-		"to":             p.Sprint("To:"),
-		"search":         p.Sprint("Search"),
-		"bcu":            p.Sprint("Bitcoin per unit (BTC/15min)"),
-		"create":         p.Sprint("Create"),
-	}
-}
--- a/pages/help/appointments.go
+++ /dev/null
@@ -1,52 +1,0 @@
-package help
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth | router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "help/appointments",
-		Data:   appointments,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func appointments(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":             p.Sprintf("Olmax Medical | FAQ"),
-		"mainHeader":        p.Sprintf("Olmax Medical"),
-		"requestHeader":     p.Sprintf("Appointment Requests"),
-		"statusHeader":      p.Sprintf("I am a patient. How do I check the status of my appointment?"),
-		"statusBody":        p.Sprintf("Once an appointment request is submitted, the physician has 4 to 12 hrs to replay. Depending on the urgency. If you would like a reply within 4 hr for urgent consults, an extra fee can be payed. Otherwise doctors have 12 hrs to reply to appointment request."),
-		"scheduleHeader":    p.Sprintf("Should I clear my schedule if I have no heard back from my doctor?"),
-		"scheduleBody":      p.Sprintf("If you do not recieve a confimation email by 12 hrs, then a full refund will be returned to your bitcoin account along with an email stating that an appointment could not be made"),
-		"expiresHeader":     p.Sprintf("What happens if my appointment request is declined or expires?"),
-		"expiresBody":       p.Sprintf("If you recieve an email confirming a cancelation of decline, bitcoin will be returned to your account infull, then you may seek another appointment"),
-		"emailHeader":       p.Sprintf("I did not recieve an email confirming nor denying my request"),
-		"emailBody1":        p.Sprintf("Make sure your email address is correct"),
-		"emailBody2":        p.Sprintf("We may be sending emails to an old or incorrect email address. To see or change the email address associated with your account, log in to your Olmax account from a desktop computer and follow the steps below:"),
-		"emailBody3":        p.Sprintf("1.) Go to Edit Profile."),
-		"emailBody4":        p.Sprintf("2.) Look for the Email Address field. Make sure your address is correct."),
-		"emailBody5":        p.Sprintf("3.) If it is incorrect, add the correct address and click Save."),
-		"notifyHeader":      p.Sprintf("Check your email notification settings"),
-		"notifyBody":        p.Sprintf("We'll only send the emails you tell us you want. To check your email notification settings, log in to your Olmax account from a desktop computer and follow the steps below:"),
-		"notifyBody1":       p.Sprintf("1.) Go to your Notification Settings."),
-		"notifyBody2":       p.Sprintf("2.) Look for the \"Email Settings\" field. Make sure you have chosen the email types you want to receive."),
-		"notifyBody3":       p.Sprintf("3.) After adding or removing checkmarks from the right boxes, scroll to the bottom of the page and click Save."),
-		"inboxSearchHeader": p.Sprintf("Search all messages in your email inbox"),
-		"inboxSearchBody":   p.Sprintf("Sometimes emails can get lost in your inbox. In your email account, search for terms like \"Olmax Medical\", \"Appointment\", \"Verification\", or other words related to the email you're looking for."),
-		"checkSpamHeader":   p.Sprintf("Check your spam and other email filters"),
-		"checkSpamBody":     p.Sprintf("It's possible your email provider mistakenly sent our messages to your spam or junk folder. To avoid this:"),
-		"checkSpamBody1":    p.Sprintf("1.) Remove Olmax messages from your spam list"),
-		"checkSpamBody2":    p.Sprintf("2.) Add nemo@olmax.com, halfwit@olmax.com, and services@olmax.com to your personal email address book"),
-		"checkSpamAdd":      p.Sprintf("If you have other filters or routing rules in your email account that may have sorted Olmax emails elsewhere, be sure to check those, too.</br>Check for issues with your email service provider."),
-		"deliveryHeader":    p.Sprintf("Depending on your provider, emails can take up to a few hours to be delivered. If undelivered or delayed emails continue to be an issue, check with your provider to see if there are any configuration issues or problems with their network that might be affecting your account."),
-		"blockHeader":       p.Sprintf("If your country blocks Olmax Medical?"),
-		"blockBody":         p.Sprintf("You can bypass their firewall using tunnel software such as a VPN,  or Tor software. See the following for more information: "),
-	}
-}
--- a/pages/help/catalog.go
+++ /dev/null
@@ -1,24 +1,0 @@
-package help
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth | router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "help/catalog",
-		Data:   catalog,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func catalog(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":      p.Sprintf("Olmax Medical | Our Doctors"),
-		"mainHeader": p.Sprintf("Olmax Medical"),
-	}
-}
--- a/pages/help/contacting.go
+++ /dev/null
@@ -1,34 +1,0 @@
-package help
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth | router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "help/contacting",
-		Data:   contacting,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func contacting(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":          p.Sprintf("Olmax Medical | FAQ"),
-		"mainHeader":     p.Sprintf("Olmax Medical"),
-		"contactHeader":  p.Sprintf("Contacting Physician"),
-		"contactBody":    p.Sprintf("You may make contact with your doctor as soon as the appointment is confirmed."),
-		"scheduleHeader": p.Sprintf("Do I need to pay before scheduling an appointment?"),
-		"scheduleBody":   p.Sprintf("Yes, you must submit payment in order to secure appointment contract. Your payment will be held in escrow until the visit is finalized. Once you submit fees, we will contact the physician and give him or her your medical information. The doctor will then confirm appointment, and an email or text will be sent to you, along with the physicians contact information. Fees are structured in amount of bitcoin (BTC) per unit(U) time (BTC/U). Every unit (U) is equivalent to 15 min, time spent in visit will be pre-determined, and visits going longer that what was agreed upon will not cost extra. All new consults must be a minimum of 2 units, and repeat visits can be a minimum of 1 unit."),
-		"chargedHeader":  p.Sprintf("When will I be charged?"),
-		"chargedBody":    p.Sprintf("Bitcoin must be paid in full upon deployment or acceptance of contract."),
-		"anycurrHeader":  p.Sprintf("Can I pay with any currency?"),
-		"anycurrBody":    p.Sprintf("No."),
-		"blocksHeader":   p.Sprintf("If your country blocks Olmax Medical?"),
-		"blocksBody":     p.Sprintf("You can bypass their firewall using tunnel software such as a VPN, or Tor software. See the following for more information: "),
-	}
-}
--- a/pages/help/help.go
+++ /dev/null
@@ -1,47 +1,0 @@
-package help
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth | router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "help/faq",
-		Data:   faq,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func faq(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":             p.Sprintf("Olmax Medical | Help"),
-		"mainHeader":        p.Sprintf("Olmax Medical"),
-		"helpHeader":        p.Sprintf("How can we help?"),
-		"topics":            p.Sprintf("Suggested Topics"),
-		"appointmentHeader": p.Sprintf("Appointment Requests"),
-		"appointmentStatus": p.Sprintf("I am a patient. How do I check the status of my appointment?"),
-		"appointmentClear":  p.Sprintf("Should I clear my schedule if I have not heard back from the doctor?"),
-		"appointmentExpire": p.Sprintf("What happens if my appointment request is declined or expires?"),
-		"paymentHeader":     p.Sprintf("Payment Methods"),
-		"paymentEdit":       p.Sprintf("How do I edit or remove a payment method?"),
-		"paymentBitcoin":    p.Sprintf("What is Bitcoin?"),
-		"paymentBitcoinHow": p.Sprintf("How do I use Bitcoin to pay?"),
-		"paymentAdd":        p.Sprintf("How can I add another appointment or business address to my receipt?"),
-		"verify":            p.Sprintf("Verification"),
-		"verifyPhone":       p.Sprintf("How do I verify my phone number?"),
-		"verifyEmail":       p.Sprintf("Why didn't I get my email notification?"),
-		"verifyLicense":     p.Sprintf("What is a Verified Medical License?"),
-		"priceHeader":       p.Sprintf("Prices & Fees"),
-		"priceDetermined":   p.Sprintf("How is the price determined for my appointment?"),
-		"priceWhen":         p.Sprintf("When will I be charged?"),
-		"priceCurrency":     p.Sprintf("Can I pay with any currency?"),
-		"contactHeader":     p.Sprintf("Contacting A Physician"),
-		"contactStatus":     p.Sprintf("What does each appointment status mean?"),
-		"contactHow":        p.Sprintf("How do I make an appointment on Olmax?"),
-		"viewall":           p.Sprintf("-View all"),
-	}
-}
--- a/pages/help/paymentmethods.go
+++ /dev/null
@@ -1,41 +1,0 @@
-package help
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth | router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "help/paymentmethods",
-		Data:   paymethod,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func paymethod(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":            p.Sprint("Olmax Medical | FAQ"),
-		"mainHeader":       p.Sprint("Olmax Medical"),
-		"paymentHeader":    p.Sprint("Payment Methods"),
-		"paymentBody":      p.Sprintf("All payments will be done via "),
-		"whatBTCHeader":    p.Sprintf("What is Bitcoin? "),
-		"whatBTCBody":      p.Sprint("Bitcoin is a form of electronic cash without a central bank or single administrator that can be sent from user to user on the peer-to-peer bitcoin network without the need for intermediaries."),
-		"chargedHeader":    p.Sprint("When will I be charged?"),
-		"chargedBody":      p.Sprint("Once you decide on which doctor you would like to make an appointment with, you will be asked to deposit bitcoin fund into a dedicated wallet where it will be held in escrow until visit is complete. If visit is cannot be completed, the funds will be deposited back to the original wallet in full."),
-		"anyCoinHeader":    p.Sprint("Can I pay with any currency?"),
-		"anyCoinBody":      p.Sprint("No"),
-		"editWalletHeader": p.Sprint("How do I edit or remove a bitcoin wallet?"),
-		"editWalletBody":   p.Sprint("If you choose to pay with a certain wallet address when you make an appointment request, you can edit or remove wallet address from your Olmax Medical account after bitcoin is out of escrow, pending or active consult."),
-		"delWalletHeader":  p.Sprint("Removing or adding personal bitcoin wallets"),
-		"delWalletBody":    p.Sprint("You can manage the bitcoin wallets in the Account section of your profile:"),
-		"delWalletBody1":   p.Sprint("1.) Click Wallet"),
-		"delWalletBody2":   p.Sprint("2.) Click Change Wallet Address to add a new wallet to your account"),
-		"otherCoinNote":    p.Sprint("Note: At this time, it's only possible to make payments with bitcoin. All other currencies are not supported."),
-		"blockedHeader":    p.Sprint("If your country blocks Olmax Medical?"),
-		"blockedBody":      p.Sprintf("You can bypass their firewall using tunnel software such as a VPN or Tor software. See the following for more information: "),
-	}
-}
--- a/pages/help/pricesandfees.go
+++ /dev/null
@@ -1,34 +1,0 @@
-package help
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth | router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "help/pricesandfees",
-		Data:   pricefee,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func pricefee(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":           p.Sprintf("Olmax Medical | FAQ"),
-		"mainHeader":      p.Sprintf("Olmax Medical"),
-		"priceHeader":     p.Sprintf("Prices & Fees"),
-		"priceBody":       p.Sprintf("Prices and fees are for the most part determined by doctors and patients."),
-		"determineHeader": p.Sprintf("How is the price determined for my appointment?"),
-		"determineBody":   p.Sprintf("Prices are set by who deploys the contract (doctor or patient). Fees are structured in a amount of bitcoin (BTC) per unit. In which a unit of time equals 15 mins. All new consults must be a minimum of 2 units, and repeat visits can be 1 unit."),
-		"chargedHeader":   p.Sprintf("When will I be charged?"),
-		"chargedBody":     p.Sprintf("Bitcoin must be paid in full upon deployment or acceptance of contract."),
-		"currencyHeader":  p.Sprintf("Can I pay with any currency?"),
-		"currencyBody":    p.Sprintf("No"),
-		"blockHeader":     p.Sprintf("If your country blocks Olmax Medical?"),
-		"blockBody":       p.Sprintf("You can bypass their firewall using tunnel software such as a VPN or Tor software. See the following for more information: "),
-	}
-}
--- a/pages/help/provider.go
+++ /dev/null
@@ -1,47 +1,0 @@
-package help
-
-import (
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth | router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "help/provider",
-		Data:   provider,
-		Extra:  plugins.Services,
-	}
-	router.AddPage(b)
-}
-
-func provider(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":              p.Sprintf("Olmax Medical | Become A Provider"),
-		"specialtyHeader":    p.Sprintf("Specialty"),
-		"mainHeader":         p.Sprintf("Become A Provider"),
-		"earn":               p.Sprintf("Find out what you could earn"),
-		"getStartedHeader":   p.Sprintf("Get Started"),
-		"getStartedlink":     p.Sprintf("Get Started"),
-		"providerWhy":        p.Sprintf("Why become a provider on Olmax?"),
-		"whyText":            p.Sprintf("No matter what your specialty, Olmax makes it simple and secure to reach millions of patients looking for doctors with unique skills and specialties, just like yours."),
-		"control":            p.Sprintf("You're in control"),
-		"controlText":        p.Sprintf("With Olmax, you're in full control of your availability, prices, medical management, and how you interact with patients. You can set appointment times and handle the process however you like."),
-		"everyStep":          p.Sprintf("We're there at every step"),
-		"everyStepText":      p.Sprintf("Olmax offers tools, service tips, 24/7 support, and an on-line community of experienced physicians for questions and sharing ideas for success."),
-		"provider":           p.Sprintf("How to become an Olmax Provider"),
-		"createProfile":      p.Sprintf("Create your profile"),
-		"createProfileText":  p.Sprintf("It's free and easy to create a profile on Olmax. Describe your resume, how many patients you can accomodate, set your own times, and add photos and details about yourself."),
-		"welcomePatient":     p.Sprintf("Welcome patients"),
-		"welcomePatientText": p.Sprintf("Communicate with patients via 3rd party applications, or personal telephone."),
-		"getPaid":            p.Sprintf("Get Paid"),
-		"getPaidText":        p.Sprintf("Olmax's secure payment system means you will never see a patient without compensation, or have to deal with money directly. Patienst are charged before appointments, and you are paid after the visit is completed. We embrace the future, therefore payments will be via Bitcoin only."),
-		"safety":             p.Sprintf("Safety on Olmax"),
-		"trust":              p.Sprintf("Olmax is built on trust"),
-		"trustText":          p.Sprintf("All Olmax physicians must: submit a profile photo, medical diplomas, residency certification or equivalent, verify their phone, email, government ID, and background checks. Patients and physicians can each publish reviews after visit conclusions keeping everyone accountable and respectful."),
-		"seeingPatients":     p.Sprintf("Start seeing patients"),
-	}
-}
--- a/pages/help/verification.go
+++ /dev/null
@@ -1,32 +1,0 @@
-package help
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth | router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "help/verification",
-		Data:   verification,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func verification(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":        p.Sprintf("Olmax Medical | FAQ"),
-		"mainHeader":   p.Sprintf("Olmax Medical"),
-		"verifyHeader": p.Sprintf("Verification"),
-		"verifyBody":   p.Sprintf("Profile information such as government ID, diplomas, phone numbers, and emails will will be verified before being posted on Olmax Medical website."),
-		"phoneHeader":  p.Sprintf("How do I verify my phone number?"),
-		"phoneBody":    p.Sprintf("Once you have submitted a phone number, you can either receive a text message or call with a confirmation number."),
-		"noNoteHeader": p.Sprintf("Why did I not get a notification email?"),
-		"noNoteBody":   p.Sprintf("Please refer to the following help page: "),
-		"blockHeader":  p.Sprintf("If your country blocks Olmax Medical?"),
-		"blockBody":    p.Sprintf("You can bypass their firewall using tunnel software such as a VPN or Tor software. See the following for more information: "),
-	}
-}
--- a/pages/index.go
+++ /dev/null
@@ -1,47 +1,0 @@
-package pages
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth | router.DoctorAuth | router.PatientAuth,
-		CSS:    "index.css",
-		Path:   "index",
-		Data:   index,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func index(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":            p.Sprintf("Olmax Medical | Welcome"),
-		"name":             p.Sprintf("Olmax Medical"),
-		"countryText":      p.Sprintf("Country"),
-		"specialty":        p.Sprintf("Specialty"),
-		"findDoctor":       p.Sprintf("Find a Doctor"),
-		"appointmentDates": p.Sprintf("Appointment Dates:"),
-		"from":             p.Sprintf("From:"),
-		"to":               p.Sprintf("To:"),
-		"appointmentTimes": p.Sprintf("Appointment Times"),
-		"startTime":        p.Sprintf("Start Time:"),
-		"endTime":          p.Sprintf("End Time:"),
-		"search":           p.Sprintf("Search"),
-		"whoWeAre":         p.Sprintf("Who We Are"),
-		"aboutUs":          p.Sprintf("Olmax Medical is a world wide network of physicians and patients that enables them to communicate, meet virtually, and negotiate payment on a peer to peer basis, without the interference of insurance giants. We provide a platform where the economics of <i>laissez-fairedes</i> (free-trade) will allow both physicians and patients to negotiate fee for service. Our website provide a platform where both patients and doctors form around the world can deploy customized contracts describing, in detail, the terms of health care. The cost, time, and duration of virtual clinic visits will be pre-determined on contracts posted on our website. The contracts are written by either doctor or patient. Contracts can be created, bought, and sold by anyone, because we believe health care should be available to everyone. It will be our work to investigate and verify physician status. Once doctors are verified, patients will have the opportunity to rate physician performance and bedside manners."),
-		"secondOpinions":   p.Sprintf("Second Opinions"),
-		"fromHome":         p.Sprintf("Since the time of Hippocrates, patients and doctors were limited to serving and receiving care from physician in their more local community. With our platform patients will not be tied to HMOs or managed health care. In other words, insurance companies or government decisions will no longer chain patients to the type and quality of health care they receive. Doctors with extremely rare specialties will be able to serve communities thousands of miles away from them, and from the comfort of their home if they so desire"),
-		"anonymity":        p.Sprintf("Anonymity"),
-		"anonText":         p.Sprintf("Patients will be encouraged to use anonymous names. Medical records are kept between patients and physicians, they are not stored on our servers."),
-		"wholeWorld":       p.Sprintf("Access to Physicians from around the world"),
-		"wholeWorldText":   p.Sprintf("Physicians from around the world will be able to join our network, see patients from anywhere at anytime."),
-		"payment":          p.Sprintf("Payment"),
-		"paymentText":      p.Sprintf("Payments will be made with Bitcoin. Minimal fees will be charged by our website for holding the cryptocurrency until clinical visits are complete."),
-		"copyright":        p.Sprintf("Copyright 2017, 2018, 2019"),
-		"seeMore":          p.Sprintf("See More"),
-		"doctorsFrom":      p.Sprintf("What are patients saying about our doctors from"),
-	}
-}
--- a/pages/login.go
+++ /dev/null
@@ -1,31 +1,0 @@
-package pages
-
-import (
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth,
-		CSS:    "",
-		Path:   "login",
-		Data:   login,
-		Extra:  plugins.FormErrors,
-	}
-	router.AddPage(b)
-}
-
-func login(p *message.Printer) map[string]interface{} {
-	// TODO: Also add in the error messages here
-	return map[string]interface{}{
-		"title":          p.Sprint("Olmax Medical | Login"),
-		"continue":       p.Sprint("Please login to continue"),
-		"greeting":       p.Sprint("Welcome back!"),
-		"email":          p.Sprint("Email:"),
-		"password":       p.Sprint("Password:"),
-		"forgotPassword": p.Sprint("Forgot your password?"),
-		"login":          p.Sprint("Login"),
-	}
-}
--- a/pages/messages.go
+++ /dev/null
@@ -1,25 +1,0 @@
-package pages
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "messages",
-		Data:   messages,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func messages(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":      p.Sprintf("Olmax Medical | Messages"),
-		"mainHeader": p.Sprintf("You currently have no messages."),
-		"messages":   p.Sprintf("Previous messages: Click here"),
-	}
-}
--- a/pages/newpassword.go
+++ /dev/null
@@ -1,28 +1,0 @@
-package pages
-
-import (
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth,
-		CSS:    "",
-		Path:   "newpassword",
-		Data:   newPassword,
-		Extra:  plugins.FormToken | plugins.FormErrors,
-	}
-	router.AddPage(b)
-}
-
-func newPassword(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":    p.Sprintf("Olmax Medical | Login"),
-		"reset":    p.Sprint("Enter new password"),
-		"password": p.Sprint("Enter password"),
-		"reenter":  p.Sprint("Re-enter password"),
-		"update":   p.Sprint("Update"),
-	}
-}
--- a/pages/patient/appointments.go
+++ /dev/null
@@ -1,27 +1,0 @@
-package patient
-
-import (
-	"html/template"
-
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.PatientAuth,
-		CSS:    "",
-		Path:   "patient/appointments",
-		Data:   appointments,
-		Extra:  0, // call function to look up appointments here
-	}
-	router.AddPage(b)
-}
-
-func appointments(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":      p.Sprintf("Olmax Medical | Appointments"),
-		"mainHeader": p.Sprintf("You currently have no appointments pending."),
-		"mainBody":   p.Sprintf("If you have submitted payment, and do not see appointment scheduled on this page; please refer to the %s section.", template.HTML(`<a href="help.html">help</a>`)),
-	}
-}
--- a/pages/patient/offer.go
+++ /dev/null
@@ -1,33 +1,0 @@
-package patient
-
-import (
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.PatientAuth,
-		CSS:    "",
-		Path:   "patient/offer",
-		Data:   offer,
-		Extra:  plugins.Services | plugins.FormErrors,
-	}
-	router.AddPage(b)
-}
-
-func offer(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":           p.Sprint("Olmax Medical | Create Offer"),
-		"mainHeader":      p.Sprint("Create An Offer"),
-		"specialty":       p.Sprint("Specialty"),
-		"specialtyHeader": p.Sprint("Physician Specialty"),
-		"bcu":             p.Sprint("Bitcoin Per Unit"),
-		"rate":            p.Sprint("15/min"),
-		"dates":           p.Sprint("Dates"),
-		"from":            p.Sprint("From: "),
-		"to":              p.Sprint("To: "),
-		"deploy":          p.Sprint("Deploy Contract"),
-	}
-}
--- a/pages/patient/profile.go
+++ /dev/null
@@ -1,24 +1,0 @@
-package patient
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.PatientAuth,
-		CSS:    "",
-		Path:   "patient/profile",
-		Data:   profile,
-		Extra:  0, // listPendingAppointments
-	}
-	router.AddPage(b)
-}
-
-func profile(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":          p.Sprintf("Olmax Medical | Profile"),
-		"greetingHeader": p.Sprintf("Hello "),
-	}
-}
--- a/pages/patient/symptoms.go
+++ /dev/null
@@ -1,50 +1,0 @@
-package patient
-
-import (
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.PatientAuth,
-		CSS:    "",
-		Path:   "patient/symptoms",
-		Data:   symptoms,
-		Extra:  plugins.FormErrors,
-	}
-	router.AddPage(b)
-}
-
-func symptoms(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":                p.Sprintf("Olmax Medical | Create Profile"),
-		"createHeader":         p.Sprintf("Create Patient Profile"),
-		"profileHeader":        p.Sprintf("Create Patient Profile"),
-		"formHeader":           p.Sprintf("Please submit some information regarding your consult."),
-		"birthdate":            p.Sprintf("When were you born?"),
-		"gender":               p.Sprintf("What is your biological gender?"),
-		"visitReason":          p.Sprintf("Please give a brief statement regarding the main reason you would like to see your doctor:"),
-		"symptomStart":         p.Sprintf("When did your symptoms start?"),
-		"symptomArea":          p.Sprintf("Where are your symptoms located? <i>part of your body</i>"),
-		"symptomDuration":      p.Sprintf("How long have these symptoms lasted?"),
-		"symptomDescription":   p.Sprintf("How would you characterize your symptoms? <i>Sharp, Dull, Ache, twisting, ets.</i>"),
-		"symptomAugment":       p.Sprintf("What makes your symptoms better, and What makes them worse?"),
-		"symptomProliferation": p.Sprintf("Does your pain travel or radiate to another part of your body?"),
-		"symptomTreatment":     p.Sprintf("Have you taken any medications for these symptoms and how much have they worked?"),
-		"feversChills":         p.Sprintf("Any fevers or Chills?"),
-		"wtGainLoss":           p.Sprintf("Any weight gain or weight loss?"),
-		"vision":               p.Sprintf("Any changes in vision?"),
-		"lung":                 p.Sprintf("Any lung issues?"),
-		"heart":                p.Sprintf("Any heart problems?"),
-		"bowel":                p.Sprintf("Any intestinal problems?"),
-		"renal":                p.Sprintf("Any kidney problems?"),
-		"musSkel":              p.Sprintf("Any problems with muscles or bones?"),
-		"neuro":                p.Sprintf("Any nervous system problmes? <i>Strokes</i>"),
-		"psych":                p.Sprintf("Any psychiatric problems? <i>Depression, anxiety</i>"),
-		"male":                 p.Sprintf("Male"),
-		"female":               p.Sprintf("Female"),
-		"legend":               p.Sprintf("Please check any of the following if you have experienced in the last 6 weeks:"),
-	}
-}
--- a/pages/resetpassword.go
+++ /dev/null
@@ -1,29 +1,0 @@
-package pages
-
-import (
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth,
-		CSS:    "",
-		Path:   "resetpassword",
-		Data:   resetPassword,
-		Extra:  plugins.FormErrors,
-	}
-	router.AddPage(b)
-}
-
-func resetPassword(p *message.Printer) map[string]interface{} {
-	// TODO: Also add in the error messages here
-	return map[string]interface{}{
-		"title":     p.Sprintf("Olmax Medical | Login"),
-		"reset":     p.Sprintf("Enter Email"),
-		"resettext": p.Sprintf("We will send a reset code to the email provided"),
-		"email":     p.Sprintf("Email:"),
-		"sendreset": p.Sprintf("Reset"),
-	}
-}
--- a/pages/signup.go
+++ /dev/null
@@ -1,34 +1,0 @@
-package pages
-
-import (
-	"github.com/olmaxmedical/olmax_go/plugins"
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.GuestAuth,
-		CSS:    "",
-		Path:   "signup",
-		Data:   signup,
-		Extra:  plugins.FormErrors,
-	}
-	router.AddPage(b)
-}
-
-func signup(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":      p.Sprintf("Olmax Medical | Sign Up"),
-		"mainHeader": p.Sprintf("Sign Up for free"),
-		"fname":      p.Sprintf("First Name:"),
-		"fnameph":    p.Sprintf("Enter your first name"),
-		"lnameph":    p.Sprintf("Enter your last name"),
-		"lname":      p.Sprintf("Last Name:"),
-		"email":      p.Sprintf("Email:"),
-		"emailph":    p.Sprintf("Enter a valid email"),
-		"pass":       p.Sprintf("Password:"),
-		"passph":     p.Sprintf("Enter password (8+ chars)"),
-		"gobutton":   p.Sprintf("Sign Up"),
-	}
-}
--- a/pages/wallet.go
+++ /dev/null
@@ -1,29 +1,0 @@
-package pages
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-	"golang.org/x/text/message"
-)
-
-func init() {
-	b := &router.Page{
-		Access: router.PatientAuth | router.DoctorAuth,
-		CSS:    "",
-		Path:   "wallet",
-		Data:   wallet,
-		Extra:  0,
-	}
-	router.AddPage(b)
-}
-
-func wallet(p *message.Printer) map[string]interface{} {
-	return map[string]interface{}{
-		"title":      p.Sprintf("Olmax Medical | Wallet"),
-		"mainHeader": p.Sprintf("Wallet"),
-		"funds":      p.Sprintf("0 BTC"),
-		"current":    p.Sprintf("NO FUNDS CURRENTLY HELD IN ESCROW"),
-		"deposit":    p.Sprintf("Deposit Funds"),
-		"onlyHeader": p.Sprintf("Send only Bitcoin (BTC) to this address"),
-		"onlyBody":   p.Sprintf("Sending any other digital asset, including Bitcoin Cash (BCH), will result in permanent loss."),
-	}
-}
--- a/plugins/appointments.go
+++ /dev/null
@@ -1,25 +1,0 @@
-package plugins
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-)
-
-// AddAppointment registers an appointment into the appointment book
-// TODO(halfwit) message/email client to fill out Symptoms form
-const AddAppointment router.PluginMask = 1 << 1
-
-func init() {
-	b := &router.Plugin{
-		Name:     "Add Appointments",
-		Run:      nil,
-		Validate: addAppt,
-	}
-	router.AddPlugin(b, AddAppointment)
-}
-
-func addAppt(s *router.Request) error {
-	// get &id=
-	// Auth user and requisite key
-	// TODO(halfwit) create unique key in patient/appointments 
-	return nil
-}
--- a/plugins/bookings.go
+++ /dev/null
@@ -1,22 +1,0 @@
-package plugins
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-)
-
-// ListBookings retreives a list of all upcoming bookings for a given doctor
-const ListBookings router.PluginMask = 1 << 2
-
-func init() {
-	b := &router.Plugin{
-		Name:     "List Bookings",
-		Run:      nil,
-		Validate: listBookings,
-	}
-	router.AddPlugin(b, ListBookings)
-}
-
-func listBookings(s *router.Request) error {
-	
-	return nil
-}
--- a/plugins/countries.go
+++ /dev/null
@@ -1,96 +1,0 @@
-package plugins
-
-import (
-	"fmt"
-	"sort"
-	"strings"
-
-	"github.com/olmaxmedical/olmax_go/router"
-	"github.com/pariz/gountries"
-	"golang.org/x/text/message"
-)
-
-// Countries - Populate a localized spinner to select country
-const Countries router.PluginMask = 1 << 3
-
-// Country - Mapping token to internationalized country code
-type Country struct {
-	ID   string
-	Name string
-}
-
-type countries struct {
-	list []gountries.Country
-}
-
-var cache *countries
-
-func init() {
-	var l []gountries.Country
-	c := gountries.New()
-	for _, c := range c.FindAllCountries() {
-		l = append(l, c)
-	}
-	cache = &countries{
-		list: l,
-	}
-	sort.Sort(cache)
-	b := &router.Plugin{
-		Name:     "country",
-		Run:      listCountries,
-		Validate: validateCountries,
-	}
-	router.AddPlugin(b, Countries)
-}
-
-// Len - For Sort implementation
-func (c *countries) Len() int {
-	return len(c.list)
-}
-
-// Less - For Sort implementation
-func (c *countries) Less(i, j int) bool {
-	switch strings.Compare(c.list[i].Name.Common, c.list[j].Name.Common) {
-	case -1:
-		return true
-	default:
-		return false
-	}
-}
-
-// Swap - For Sort implementation
-func (c *countries) Swap(i, j int) {
-	tmp := c.list[i]
-	c.list[i] = c.list[j]
-	c.list[j] = tmp
-}
-
-func listCountries(r *router.Request) map[string]interface{} {
-	p := r.Printer()
-	// TODO(halfwit): Use Request to get a localized country name
-	c := make(map[string]interface{})
-	c["label"] = p.Sprint("Select country/countries")
-	for _, item := range cache.list {
-		c[item.Name.Common] = item.Name.Common
-	}
-	return c
-}
-
-func validateCountries(r *router.Request) error {
-	s := r.Request()
-	for _, c := range s.PostFormValue("country") {
-		if msg := checkCountry(r.Printer(), c); msg != nil {
-			return msg
-		}
-	}
-	return nil
-}
-
-func checkCountry(p *message.Printer, country rune) error {
-	for _, item := range cache.list {
-		if item.Name.Common == string(country) {
-			return nil
-		}
-	}
-	return fmt.Errorf("%s", p.Sprint("No country entered/nil value entered"))
-}
--- a/plugins/doctor.go
+++ /dev/null
@@ -1,55 +1,0 @@
-package plugins
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-)
-
-// ListDoctors - Bitmask to list doctors of in client country
-const ListDoctors router.PluginMask = 1 << 4
-
-type doctor struct {
-	Image     string
-	AlmaMater string
-	Name      string
-	Residency string
-	Current   string
-	Country   string
-	Specialty string
-	Rate      string
-}
-
-func init() {
-	b := &router.Plugin{
-		Name:     "doctors",
-		Run:      ListDocs,
-		Validate: nil,
-	}
-	router.AddPlugin(b, ListDoctors)
-}
-
-// ListDocs - Query db and return list of doctors in country
-// These may need eventual localization for any bilingual doctors we have
-func ListDocs(r *router.Request) map[string]interface{} {
-	return map[string]interface{}{
-		"Mark Abuzamzam, MD": &doctor{
-			Image:     "AbuzamzamMD.jpg",
-			AlmaMater: "University of Southern California School of Medicine",
-			Residency: "University of Southern California, San Diego. Internal Medicine Residency",
-			Name:      "Mark Abuzamzam, MD",
-			Current:   "Current Faculty at University of California Irvine Program Director",
-			Country:   "United States of America",
-			Specialty: "Internal Medicine and Addictions Medicine",
-			Rate:      "0.0013 BTC",
-		},
-		"Martha Woodfin, MD": &doctor{
-			Image:     "WoodfinMD.jpg",
-			Name:      "Martha Woodfin, MD",
-			AlmaMater: "University Seoul School of Medicine",
-			Residency: "University of Las Vegas Nevada, Pediatric Medicine Residency",
-			Current:   "Current Staff at Mercy Hospital Jackson NC",
-			Country:   "United States of America",
-			Specialty: "Internal Medicine",
-			Rate:      "0.0011 BTC",
-		},
-	}
-}
--- a/plugins/email.go
+++ /dev/null
@@ -1,83 +1,0 @@
-package plugins
-
-import (
-	"errors"
-	"log"
-	"mime/multipart"
-
-	"github.com/olmaxmedical/olmax_go/email"
-	"github.com/olmaxmedical/olmax_go/router"
-)
-
-// EmailForm - Patient form to gmail
-const EmailForm router.PluginMask = 1 << 5
-
-// SendSignup - Send account creation validation email
-const SendSignup router.PluginMask = 1 << 6
-
-// SendReset - Send password reset email
-const SendReset router.PluginMask = 1 << 7
-
-func init() {
-	b := &router.Plugin{
-		Name:     "emailform",
-		Run:      nil,
-		Validate: emailForm,
-	}
-	router.AddPlugin(b, EmailForm)
-	c := &router.Plugin{
-		Name:     "signupEmail",
-		Run:      nil,
-		Validate: signupEmail,
-	}
-	router.AddPlugin(c, SendSignup)
-	d := &router.Plugin{
-		Name:     "resetPassword",
-		Run:      nil,
-		Validate: resetPassword,
-	}
-	router.AddPlugin(d, SendReset)
-}
-
-func signupEmail(s *router.Request) error {
-	r := s.Request()
-	first := r.PostFormValue("fname")
-	last := r.PostFormValue("lname")
-	address := r.PostFormValue("email")
-	pass := r.PostFormValue("pass")
-	email.SendSignup(first, last, address, pass, s.Printer())
-	return nil
-}
-
-func resetPassword(s *router.Request) error {
-	p := s.Printer()
-	r := s.Request()
-	email.SendReset(r.PostFormValue("email"), p)
-	return nil
-}
-
-func emailForm(s *router.Request) error {
-	p := s.Printer()
-	r := s.Request()
-	r.ParseMultipartForm(10 << 20) // parse up to 10MB
-	if r.PostFormValue("name") == "" || r.PostFormValue("email") == "" {
-		return errors.New(p.Sprint("Missing name or email in form. Please contact us at olmaxmedical@gmail.com"))
-	}
-	if b, ok := r.Form["sendto"]; !ok || b[0] == "" {
-		return errors.New(p.Sprint("Missing value for target email. Please contact us at olmaxmedical.gmail.com"))
-	}
-	attachments := make(map[string]multipart.File)
-	m := r.MultipartForm
-	for _, headers := range m.File {
-		for _, header := range headers {
-			file, err := header.Open()
-			if err != nil { //non fatal, log any oddities and continue
-				log.Println(err)
-				continue
-			}
-			attachments[header.Filename] = file
-		}
-	}
-	email.SendForm(r.Form, p, attachments)
-	return nil
-}
--- a/plugins/errors.go
+++ /dev/null
@@ -1,28 +1,0 @@
-package plugins
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-)
-
-// FormErrors - A list of errors present on a POST request
-const FormErrors router.PluginMask = 1 << 8
-
-func init() {
-	b := &router.Plugin{
-		Name:     "errors",
-		Run:      GetFormErrors,
-		Validate: nil,
-	}
-	router.AddPlugin(b, FormErrors)
-}
-
-// GetFormErrors - return the client a list of any errors in the form
-func GetFormErrors(r *router.Request) map[string]interface{} {
-	s := r.Session()
-	if s == nil {
-		return nil
-	}
-	return map[string]interface{}{
-		"errors": s.Get("errors"),
-	}
-}
--- a/plugins/messages.go
+++ /dev/null
@@ -1,29 +1,0 @@
-package plugins
-
-import (
-	"github.com/olmaxmedical/olmax_go/router"
-)
-
-// Messages - list all messages by key for use in a message template
-const Messages router.PluginMask = 1 << 9
-
-func init() {
-	b := &router.Plugin{
-		Name:     "messages",
-		Run:      GetMessages,
-		Validate: nil,
-	}
-	router.AddPlugin(b, Messages)
-}
-
-// GetMessages - return a map of message structs
-func GetMessages(r *router.Request) map[string]interface{} {
-	s := r.Session()
-	if s == nil {
-		return nil
-	}
-	return map[string]interface{}{
-		// No, this won't actually do anything.
-		"messages": s.Get("messages"),
-	}
-}
--- a/plugins/offers.go
+++ /dev/null
@@ -1,19 +1,0 @@
-package plugins
-
-import "github.com/olmaxmedical/olmax_go/router"
-
-// MakeOffer - Request a time slot with doctor
-const MakeOffer router.PluginMask = 1 << 10
-
-func init() {
-	b := &router.Plugin{
-		Name:     "offer",
-		Run:      nil,
-		Validate: offer,
-	}
-	router.AddPlugin(b, MakeOffer)
-}
-
-func offer(s *router.Request) error {
-	return nil
-}
--- a/plugins/password.go
+++ /dev/null
@@ -1,62 +1,0 @@
-package plugins
-
-import (
-	"errors"
-
-	"github.com/olmaxmedical/olmax_go/db"
-	"github.com/olmaxmedical/olmax_go/router"
-)
-
-// ValidateLogin - Check user/pass combo exists
-const ValidateLogin router.PluginMask = 1 << 11
-
-// ResetPassword - Update database entry for password
-const ResetPassword router.PluginMask = 1 << 12
-
-func init() {
-	b := &router.Plugin{
-		Name:     "login",
-		Run:      nil,
-		Validate: login,
-	}
-	router.AddPlugin(b, ValidateLogin)
-	c := &router.Plugin{
-		Name:     "setPassword",
-		Run:      nil,
-		Validate: setPass,
-	}
-	router.AddPlugin(c, ResetPassword)
-}
-
-func login(s *router.Request) error {
-	r := s.Request()
-	us := s.Session()
-	p := s.Printer()
-	user := r.PostFormValue("email")
-	pass := r.PostFormValue("pass")
-	if db.ValidateLogin(user, pass) {
-		us.Set("username", user)
-		us.Set("login", "true")
-		us.Set("role", db.UserRole(user))
-		us.Set("token", db.NewToken())
-		return nil
-	}
-	return errors.New(p.Sprint("Invalid login"))
-}
-
-func setPass(s *router.Request) error {
-	r := s.Request()
-	p := s.Printer()
-
-	pass := r.PostFormValue("password")
-	repeat := r.PostFormValue("reenter")
-	if pass != repeat {
-		return errors.New(p.Sprint("Passwords do not match"))
-	}
-	token := r.PostFormValue("token")
-	if !db.FindTempEntry(token) {
-		return errors.New(p.Sprint("Session expired"))
-	}
-	db.UpdateUserPassword(token, pass)
-	return nil
-}
--- a/plugins/search.go
+++ /dev/null
@@ -1,20 +1,0 @@
-package plugins
-
-import "github.com/olmaxmedical/olmax_go/router"
-
-// Search - generic search for doctors in area
-const Search router.PluginMask = 1 << 13
-
-func init() {
-	b := &router.Plugin{
-		Name:     "search",
-		Run:      nil,
-		Validate: search,
-	}
-	router.AddPlugin(b, Search)
-}
-
-// Stuuuuubbb
-func search(r *router.Request) error {
-	return nil
-}
--- a/plugins/services.go
+++ /dev/null
@@ -1,114 +1,0 @@
-package plugins
-
-import (
-	"fmt"
-
-	"github.com/olmaxmedical/olmax_go/router"
-)
-
-// Services - Bitmask to list services in native language
-const Services router.PluginMask = 1 << 14
-
-func init() {
-	b := &router.Plugin{
-		Name:     "specialties",
-		Run:      ListServices,
-		Validate: ValidateServices,
-	}
-	router.AddPlugin(b, Services)
-}
-
-// ValidateServices - Ensure the specialties entered exist in our map
-func ValidateServices(r *router.Request) error {
-	s := r.Request()
-	var errs []string
-	for _, entry := range s.PostFormValue("specialty") {
-		switch string(entry) {
-		case "acutepain":
-		case "anasthesiology":
-		case "bariatric":
-		case "cardiology":
-		case "chiropractic":
-		case "chronic":
-		case "critcare":
-		case "dermatology":
-		case "emergency":
-		case "endocrinology":
-		case "otolaringology":
-		case "familymedicine":
-		case "gastro":
-		case "headneck":
-		case "hematology":
-		case "hepatology":
-		case "hyperbaric":
-		case "immunology":
-		case "diseases":
-		case "internal":
-		case "neonatal":
-		case "nephrology":
-		case "neurology":
-		case "neurosurgery":
-		case "obstetrics":
-		case "occupational":
-		case "opthamology":
-		case "orthopedics":
-		case "palliative":
-		case "pediatrics":
-		case "podiatry":
-		case "pulmonology":
-		case "radiology":
-		case "radiation":
-		case "transplants":
-			continue
-		default:
-			errs = append(errs, fmt.Sprintf("Unknown entry: %q\n", entry))
-		}
-		if len(errs) > 0 {
-			return fmt.Errorf("%s", errs)
-		}
-	}
-	return nil
-}
-
-// ListServices - return a list of native language representations of our medical fields
-func ListServices(r *router.Request) map[string]interface{} {
-	p := r.Printer()
-	return map[string]interface{}{
-		"label":          p.Sprint("Select specialty/specialties"),
-		"acutepain":      p.Sprint("Acute Pain Medicine"),
-		"anesthesiology": p.Sprint("Anesthesiology"),
-		"bariatric":      p.Sprint("Bariatric Surgery"),
-		"cardiology":     p.Sprint("Cardiology"),
-		"chiropractic":   p.Sprint("Chiropractics"),
-		"chronic":        p.Sprint("Chronic Pain"),
-		"critcare":       p.Sprint("Critical Care"),
-		"dermatology":    p.Sprint("Dermatology"),
-		"emergency":      p.Sprint("Emergency Medicine"),
-		"endocrinology":  p.Sprint("Endocrinology"),
-		"otolaringology": p.Sprint("Ear Nose and Throat"),
-		"familymedicine": p.Sprint("Family Medicine"),
-		"gastro":         p.Sprint("Gastrointestinology"),
-		"headneck":       p.Sprint("Head and Neck"),
-		"hematology":     p.Sprint("Hematology and Oncology"),
-		"hepatology":     p.Sprint("Hepatology"),
-		"hyperbaric":     p.Sprint("Hyperbaric"),
-		"immunology":     p.Sprint("Immunology"),
-		"diseases":       p.Sprint("Infectious Diseases"),
-		"internal":       p.Sprint("Internal Medicine"),
-		"neonatal":       p.Sprint("Neonatology"),
-		"nephrology":     p.Sprint("Nephrology"),
-		"neurology":      p.Sprint("Neurology"),
-		"neurosurgery":   p.Sprint("Neurosurgery"),
-		"obstetrics":     p.Sprint("Obstetrics and Gynecology"),
-		"occupational":   p.Sprint("Occupational Medicine"),
-		"opthamology":    p.Sprint("Opthamology"),
-		"orthopedics":    p.Sprint("Orthopedic Surgery"),
-		"palliative":     p.Sprint("Palliative Care"),
-		"pediatrics":     p.Sprint("Pediatrics"),
-		"podiatry":       p.Sprint("Podiatry"),
-		"pulmonology":    p.Sprint("Pulmonology"),
-		"radiology":      p.Sprint("Radiology"),
-		"radiation":      p.Sprint("Radiaton Oncology"),
-		"transplants":    p.Sprint("Transplant Surgery"),
-	}
-}
--- a/plugins/tokens.go
+++ /dev/null
@@ -1,29 +1,0 @@
-package plugins
-
-import (
-	"github.com/olmaxmedical/olmax_go/db"
-	"github.com/olmaxmedical/olmax_go/router"
-)
-
-// FormToken - A database-persisted one time use token to relate forms to POST requests
-const FormToken router.PluginMask = 1 << 15
-
-func init() {
-	c := &router.Plugin{
-		Name:     "formToken",
-		Run:      newFormToken,
-		Validate: validateToken,
-	}
-	router.AddPlugin(c, FormToken)
-}
-
-func validateToken(r *router.Request) error {
-	return db.ValidateToken(r.Request(), r.Session())
-}
-
-// TODO(halfwit) - database
-func newFormToken(r *router.Request) map[string]interface{} {
-	return map[string]interface{}{
-		"token": db.NewToken(),
-	}
-}
--- a/router/footer.go
+++ /dev/null
@@ -1,33 +1,0 @@
-package router
-
-import (
-	"golang.org/x/text/message"
-)
-
-func footer(p *message.Printer) map[string]string {
-	return map[string]string{
-		"faq":      p.Sprintf("FAQ"),
-		"help":     p.Sprintf("Help"),
-		"banner":   p.Sprintf("Quality Healthcare"),
-		"pay":      p.Sprintf("Payment Methods"),
-		"fees":     p.Sprintf("Prices and Fees"),
-		"verify":   p.Sprintf("Verification"),
-		"appt":     p.Sprintf("Appointments"),
-		"legal":    p.Sprintf("Legal"),
-		"privacy":  p.Sprintf("Privacy Policy"),
-		"howworks": p.Sprint("How It Works"),
-		"contact":  p.Sprint("Contact Us"),
-		"pricing":  p.Sprint("Pricing"),
-		"catalog":  p.Sprint("Catalog"),
-		"appts":    p.Sprint("Appointments"),
-		"proc":     p.Sprint("Payment Procedures"),
-		"payments": p.Sprint("Payment Methods"),
-		"phone":    p.Sprint("Call toll free"),
-		"number":   p.Sprint("1(555)555-1234"),
-		"email":    p.Sprint("Email"),
-		"partHead": p.Sprintf("Work with us!"),
-		"partner":  p.Sprintf("Become A Partner"),
-		"provider": p.Sprint("Become A Provider"),
-		"copy":     p.Sprintf("Copyright 2017, 2018, 2019"),
-	}
-}
--- a/router/forms.go
+++ /dev/null
@@ -1,66 +1,0 @@
-package router
-
-import (
-	"fmt"
-	"net/http"
-
-	"github.com/olmaxmedical/olmax_go/session"
-	"golang.org/x/text/message"
-)
-
-var formlist map[string]*Form
-
-// Form - POST requests
-type Form struct {
-	Access    Access
-	After     PluginMask
-	Path      string
-	Redirect  string
-	Validator func(r *http.Request, p *message.Printer) []string
-}
-
-func init() {
-	formlist = make(map[string]*Form)
-}
-
-// AddPost - Register a POST form from forms/
-func AddPost(f *Form) {
-	formlist[f.Path+".html"] = f
-}
-
-func parseForm(p *Request, w http.ResponseWriter, r *http.Request) (*Form, []string) {
-	var errors []string
-	form, ok := formlist[p.path]
-	if !ok {
-		errors = append(errors, "No such page")
-		return nil, errors
-	}
-	if errs := form.Validator(r, p.printer); len(errs) > 0 {
-		return nil, errs
-	}
-	for _, key := range pluginKey {
-		if (form.After&key) != 0 && pluginCache[key].Validate != nil {
-			if e := pluginCache[key].Validate(p); e != nil {
-				errors = append(errors, fmt.Sprint(e))
-				return nil, errors
-			}
-		}
-	}
-	return form, errors
-}
-
-func postform(p *Request, us session.Session, w http.ResponseWriter, r *http.Request) {
-	form, errors := parseForm(p, w, r)
-	if len(errors) > 0 && errors[0] != "nil" {
-		// NOTE(halfwit) this stashes previous entries, but does not work
-		// on multipart forms (with file uploads)
-		us.Set("errors", errors)
-		// Maybe store form args instead here in session
-		url := fmt.Sprintf("%s?%s", r.URL.String(), r.Form.Encode())
-		http.Redirect(w, r, url, 302)
-	}
-	if form != nil {
-		us.Set("errors", []string{})
-		http.Redirect(w, r, form.Redirect, 302)
-	}
-}
--- a/router/handler.go
+++ /dev/null
@@ -1,145 +1,0 @@
-package router
-
-import (
-	"fmt"
-	"net/http"
-
-	"github.com/olmaxmedical/olmax_go/db"
-	"github.com/olmaxmedical/olmax_go/email"
-	"github.com/olmaxmedical/olmax_go/session"
-	"golang.org/x/text/message"
-)
-
-// Handle specific endpoints
-type handler struct {
-	manager *session.Manager
-}
-
-func (d *handler) logout(w http.ResponseWriter, r *http.Request) {
-	d.manager.Destroy(w, r)
-	w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
-	http.Redirect(w, r, "/index.html", 302)
-}
-
-func (d *handler) normal(w http.ResponseWriter, r *http.Request) {
-	w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
-	if r.URL.Path == "/" {
-		http.Redirect(w, r, "/index.html", 302)
-		return
-	}
-	user, status, us, role := d.getUser(w, r)
-	p := &Request{
-		printer: userLang(r),
-		status:  status,
-		request: r,
-		user:    user,
-		role:    role,
-		session: us,
-		path:    r.URL.Path[1:],
-	}
-
-	switch r.Method {
-	case "GET":
-		getpage(p, w)
-	case "POST":
-		postform(p, us, w, r)
-	}
-}
-
-// TODO: This will require actual client data from the database to populate the page
-func (d *handler) profile(w http.ResponseWriter, r *http.Request) {
-	w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
-	user, status, us, role := d.getUser(w, r)
-	if status == "false" {
-		http.Redirect(w, r, "/login.html", 302)
-		return
-	}
-	if rd, ok := us.Get("redirect").(string); ok {
-		us.Delete("redirect")
-		http.Redirect(w, r, "/"+rd, 302)
-		return
-	}
-	p := &Request{
-		printer: userLang(r),
-		status:  status,
-		session: us,
-		user:    user,
-		role:    role,
-	}
-	var data []byte
-	var err error
-	switch db.UserRole(user) {
-	case db.DoctorAuth:
-		if role != db.DoctorAuth {
-			http.Error(w, "Unauthorized", 401)
-			return
-		}
-		p.path = "doctor/profile.html"
-		data, err = getData(p, "doctor")
-	case db.PatientAuth:
-		if role != db.PatientAuth {
-			http.Error(w, "Unauthorized", 401)
-			return
-		}
-		p.path = "patient/profile.html"
-		data, err = getData(p, "patient")
-	default:
-		http.Error(w, "Forbidden", 403)
-		return
-	}
-	if err != nil {
-		http.Error(w, "Service Unavailable", 503)
-		return
-	}
-	fmt.Fprintf(w, "%s", data)
-}
-
-func (d *handler) activate(w http.ResponseWriter, r *http.Request) {
-	w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
-	if len(r.URL.Path) != 46 && r.URL.Path[:9] != "/activate" {
-		http.Error(w, "Bad Request", 400)
-		return
-	}
-	email.ValidateSignupToken(w, r, r.URL.Path[10:])
-}
-
-func (d *handler) reset(w http.ResponseWriter, r *http.Request) {
-	if len(r.URL.Path) != 43 && r.URL.Path[:6] != "/reset" {
-		http.Error(w, "Bad Request", 400)
-		return
-	}
-	p := userLang(r)
-	user, _, us, _ := d.getUser(w, r)
-	token := email.NextResetToken(r.URL.Path[7:], user)
-	if token == "" {
-		us.Set("errors", [1]string{p.Sprint("Token expired")})
-		return
-	}
-	us.Set("token", token)
-	r.URL.Path = "/newpassword.html"
-	d.normal(w, r)
-}
-
-func (d *handler) getUser(w http.ResponseWriter, r *http.Request) (string, string, session.Session, db.Access) {
-	us := d.manager.Start(w, r)
-	user, ok1 := us.Get("username").(string)
-	status, ok2 := us.Get("login").(string)
-	role, ok3 := us.Get("role").(db.Access)
-	if !ok1 || !ok2 || status != "true" {
-		status = "false"
-	}
-	if !ok3 {
-		role = db.GuestAuth
-	}
-	if status == "true" {
-		us.Set("token", db.NewToken())
-	}
-	return user, status, us, role
-}
-
-func userLang(r *http.Request) *message.Printer {
-	accept := r.Header.Get("Accept-Language")
-	lang := r.FormValue("lang")
-	tag := message.MatchLanguage(lang, accept)
-	return message.NewPrinter(tag)
-}
--- a/router/header.go
+++ /dev/null
@@ -1,16 +1,0 @@
-package router
-
-import (
-	"golang.org/x/text/message"
-)
-
-func header(p *message.Printer, status string) map[string]string {
-	return map[string]string{
-		"home":    p.Sprint("Home"),
-		"login":   p.Sprint("Login"),
-		"logout":  p.Sprint("Logout"),
-		"signup":  p.Sprint("Sign Up"),
-		"profile": p.Sprint("Profile"),
-		"status":  status,
-	}
-}
--- a/router/pages.go
+++ /dev/null
@@ -1,155 +1,0 @@
-package router
-
-import (
-	"bufio"
-	"bytes"
-	"errors"
-	"fmt"
-	"html/template"
-	"net/http"
-	"os"
-	"path"
-	"strings"
-
-	"github.com/olmaxmedical/olmax_go/db"
-	"golang.org/x/text/message"
-)
-
-var pagecache map[string]*Page
-
-func init() {
-	pagecache = make(map[string]*Page)
-}
-
-// Access defines the access rights for a specific page
-type Access uint8
-
-const (
-	// GuestAuth - non registered user
-	GuestAuth Access = 1 << iota
-	// PatientAuth - normal user, added by registration process
-	PatientAuth
-	// DoctorAuth - manually added to the database
-	DoctorAuth
-)
-
-// Page defines what a client receives from a GET request
-type Page struct {
-	Access Access
-	Extra  PluginMask
-	CSS    string
-	Path   string
-	Data   func(p *message.Printer) map[string]interface{}
-	tmpl   *template.Template
-}
-
-// AddPage - register a *Page to the cache
-func AddPage(p *Page) {
-	pagecache[p.Path+".html"] = p
-}
-
-// ValidatePages - Walk all our templates, test them, and finally return applicable errors as an array
-func ValidatePages() []error {
-	var errs []error
-	hd := path.Join("templates", "header.tpl")
-	fd := path.Join("templates", "footer.tpl")
-	ld := path.Join("templates", "layout.tpl")
-	extra, err := os.Open(path.Join("templates", "plugins"))
-	if err != nil {
-		errs = append(errs, errors.New("Unable to locate templates/plugins"))
-		return errs
-	}
-	dirs, err := extra.Readdirnames(0)
-	for n, dir := range dirs {
-		dirs[n] = path.Join("templates", "plugins", dir)
-	}
-	// TODO(halfwit) Validate our plugin templates here as well
-	dirs = append(dirs, hd, fd, ld)
-	printer := message.NewPrinter(message.MatchLanguage("en"))
-	for _, item := range pagecache {
-		var err error
-		tp := path.Join("templates", item.Path) + ".tpl"
-		t := template.New(path.Base(tp))
-		// TODO(halfwit) Contemplate only adding templates for plugins each page uses
-		item.tmpl, _ = t.ParseFiles(dirs...)
-		item.tmpl, err = t.ParseFiles(tp)
-		if err != nil {
-			errs = append(errs, fmt.Errorf("parsing in %s - %v", path.Dir(item.Path), err))
-			continue
-		}
-		p := &Request{
-			printer: printer,
-			path:    item.Path + ".html",
-			role:    db.PatientAuth | db.DoctorAuth | db.GuestAuth,
-		}
-		_, err = getData(p, "")
-		if err != nil {
-			errs = append(errs, err)
-		}
-	}
-	return errs
-}
-
-func getpage(p *Request, w http.ResponseWriter) {
-	var data []byte
-	var err error
-	switch db.UserRole(p.user) {
-	case db.DoctorAuth:
-		data, err = getData(p, "doctor")
-	case db.PatientAuth:
-		data, err = getData(p, "patient")
-	default:
-		data, err = getData(p, "guest")
-	}
-	if err != nil && err.Error() == "Unauthorized" {
-		p.Session().Set("redirect", p.path)
-		http.Redirect(w, p.Request(), "/login.html", 302)
-		return
-	}
-	if err != nil {
-		http.Error(w, "Service Unavailable", 503)
-		return
-	}
-	fmt.Fprintf(w, "%s", data)
-}
-
-func getData(p *Request, in string) ([]byte, error) {
-	cache, ok := pagecache[p.path]
-	if !ok {
-		return nil, fmt.Errorf("No such page: %s", p.path)
-	}
-	if uint8(p.role)&uint8(cache.Access) == 0 {
-		return nil, errors.New("Unauthorized")
-	}
-	r := cache.Data(p.printer)
-	r["css"] = cache.CSS
-	r["header"] = header(p.printer, p.status)
-	r["footer"] = footer(p.printer)
-	r["basedir"] = getBaseDir(cache.Path)
-	// TODO(halfwit) Test chunking in to go routines if n gets too large
-	for _, key := range pluginKey {
-		if (cache.Extra&key) != 0 && pluginCache[key].Run != nil {
-			r[pluginCache[key].Name] = pluginCache[key].Run(p)
-		}
-	}
-	if p.session != nil {
-		r["username"] = p.session.Get("username")
-		if _, ok := p.session.Get("redirect").(string); ok {
-			r["redirect"] = true
-		}
-	}
-	return cache.render(r)
-}
-
-func (page *Page) render(i map[string]interface{}) ([]byte, error) {
-	var buf bytes.Buffer
-	data := bufio.NewWriter(&buf)
-	err := page.tmpl.ExecuteTemplate(data, "layout", i)
-	data.Flush()
-	return buf.Bytes(), err
-
-}
-
-func getBaseDir(fp string) string {
-	return strings.Repeat("../", strings.Count(fp, "/"))
-}
--- a/router/plugins.go
+++ /dev/null
@@ -1,49 +1,0 @@
-package router
-
-import (
-	"fmt"
-)
-
-// PluginMask - (Must be unique) ID for a plugin
-type PluginMask uint32
-
-// DEAD is a magic string to indicate a non-unique plugin key
-const DEAD PluginMask = 1
-
-var pluginCache map[PluginMask]*Plugin
-var pluginKey []PluginMask
-
-// Plugin - Provide extra data or functionality from GET/POST pages
-type Plugin struct {
-	Name     string
-	Run      func(p *Request) map[string]interface{}
-	Validate func(p *Request) error
-}
-
-func init() {
-	pluginCache = make(map[PluginMask]*Plugin)
-}
-
-// ValidatePlugins - Make sure that its mapping isn't redundant with any other
-// Plugins have external testing to validate they are correct
-func ValidatePlugins() []error {
-	errs := []error{}
-	for key, item := range pluginCache {
-		if item.Validate == nil {
-			continue
-		}
-		if (key & DEAD) != 0 {
-			errs = append(errs, fmt.Errorf("Error registering %s: Key requested already in use", item.Name))
-		}
-	}
-	return errs
-}
-
-// AddPlugin - Add Plugin to map by key
-func AddPlugin(p *Plugin, key PluginMask) {
-	if pluginCache[key] != nil {
-		key |= DEAD
-	}
-	pluginKey = append(pluginKey, key)
-	pluginCache[key] = p
-}
--- a/router/request.go
+++ /dev/null
@@ -1,35 +1,0 @@
-package router
-
-import (
-	"net/http"
-
-	"github.com/olmaxmedical/olmax_go/db"
-	"github.com/olmaxmedical/olmax_go/session"
-	"golang.org/x/text/message"
-)
-
-// Request represents an incoming GET/POST
-type Request struct {
-	printer *message.Printer
-	session session.Session
-	request *http.Request
-	user    string
-	status  string
-	path    string
-	role    db.Access
-}
-
-// Printer - returns the client's localized printer handler
-func (r *Request) Printer() *message.Printer {
-	return r.printer
-}
-
-// Session - returns the client's session
-func (r *Request) Session() session.Session {
-	return r.session
-}
-
-// Request - underlying http.Request for forms and such
-func (r *Request) Request() *http.Request {
-	return r.request
-}
--- a/router/run.go
+++ /dev/null
@@ -1,35 +1,0 @@
-package router
-
-import (
-	"crypto/tls"
-	"net/http"
-
-	"github.com/olmaxmedical/olmax_go/session"
-)
-
-// Route - All requests pass through here first
-func Route(manager *session.Manager) error {
-	d := &handler{
-		manager: manager,
-	}
-	css := http.FileServer(http.Dir("resources/css/"))
-	jss := http.FileServer(http.Dir("resources/scripts"))
-	img := http.FileServer(http.Dir("resources/images/"))
-	mux := http.NewServeMux()
-	mux.Handle("/css/", http.StripPrefix("/css/", css))
-	mux.Handle("/scripts/", http.StripPrefix("/scripts/", jss))
-	mux.Handle("/images/", http.StripPrefix("/images/", img))
-	mux.HandleFunc("/activate/", d.activate)
-	mux.HandleFunc("/reset/", d.reset)
-	mux.HandleFunc("/logout.html", d.logout)
-	mux.HandleFunc("/profile.html", d.profile)
-	mux.HandleFunc("/", d.normal)
-	//from https://github.com/denji/golang-tls (creative commons)
-	srv := &http.Server{
-		Addr:         ":8443",
-		Handler:      mux,
-		TLSConfig:    getTlsConfig(),
-		TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
-	}
-	return srv.ListenAndServeTLS("cert.pem", "key.pem")
-}
--- a/router/tls.go
+++ /dev/null
@@ -1,21 +1,0 @@
-package router
-
-import (
-	"crypto/tls"
-)
-
-func getTlsConfig() *tls.Config {
-	tlsConfig := &tls.Config{
-		MinVersion:               tls.VersionTLS12,
-		CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
-		PreferServerCipherSuites: true,
-		CipherSuites: []uint16{
-			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
-			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
-			tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
-			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
-		},
-	}
-	tlsConfig.BuildNameToCertificate()
-	return tlsConfig
-}
--- a/session/data.go
+++ /dev/null
@@ -1,116 +1,0 @@
-package session
-
-import (
-	"container/list"
-	"log"
-	"sync"
-	"time"
-)
-
-var pder = &Default{
-	list: list.New(),
-}
-
-// Store - map of clients and their sessions
-type Store struct {
-	sid   string
-	atime time.Time
-	value map[interface{}]interface{}
-}
-
-func init() {
-	pder.sessions = make(map[string]*list.Element, 0)
-	Register("default", pder)
-}
-
-// Set - register kv into manager
-func (st *Store) Set(key, value interface{}) error {
-	st.value[key] = value
-	pder.Update(st.sid)
-	return nil
-}
-
-// Get - lookup value by key
-func (st *Store) Get(key interface{}) interface{} {
-	pder.Update(st.sid)
-	if v, ok := st.value[key]; ok {
-		return v
-	}
-	return nil
-}
-
-// Delete - remove value pointed to by key
-func (st *Store) Delete(key interface{}) error {
-	delete(st.value, key)
-	pder.Update(st.sid)
-	return nil
-}
-
-// ID - return session ID
-func (st *Store) ID() string {
-	return st.sid
-}
-
-// Default - The main session used for clients on the site
-type Default struct {
-	lock     sync.Mutex
-	sessions map[string]*list.Element
-	list     *list.List
-}
-
-// Init - create session
-func (pder *Default) Init(sid string) (Session, error) {
-	pder.lock.Lock()
-	defer pder.lock.Unlock()
-	v := make(map[interface{}]interface{}, 0)
-	newsess := &Store{sid: sid, atime: time.Now(), value: v}
-	element := pder.list.PushBack(newsess)
-	pder.sessions[sid] = element
-	return newsess, nil
-}
-
-// Read - Request session by id
-func (pder *Default) Read(sid string) (Session, error) {
-	if element, ok := pder.sessions[sid]; ok {
-		return element.Value.(*Store), nil
-	}
-	return pder.Init(sid)
-}
-
-// Destroy - Remove session by id
-func (pder *Default) Destroy(sid string) error {
-	if element, ok := pder.sessions[sid]; ok {
-		delete(pder.sessions, sid)
-		pder.list.Remove(element)
-	}
-	return nil
-}
-
-// GC - Clean up all expired sessions
-func (pder *Default) GC(maxlifetime int64) {
-	log.Println("Starting GC sweep")
-	pder.lock.Lock()
-	defer pder.lock.Unlock()
-	for {
-		element := pder.list.Back()
-		if element == nil {
-			return
-		}
-		if (element.Value.(*Store).atime.Unix() + maxlifetime) >= time.Now().Unix() {
-			return
-		}
-		pder.list.Remove(element)
-		delete(pder.sessions, element.Value.(*Store).sid)
-	}
-}
-
-// Update - move session labelled with ID to top of list
-func (pder *Default) Update(sid string) error {
-	pder.lock.Lock()
-	defer pder.lock.Unlock()
-	if element, ok := pder.sessions[sid]; ok {
-		element.Value.(*Store).atime = time.Now()
-		pder.list.MoveToFront(element)
-	}
-	return nil
-}
--- a/session/manager.go
+++ /dev/null
@@ -1,122 +1,0 @@
-package session
-
-import (
-	"fmt"
-	"log"
-	"net/http"
-	"net/url"
-	"sync"
-	"time"
-
-	"github.com/google/uuid"
-)
-
-var provides = make(map[string]Provider)
-
-// Manager - Represents a particular cookie to a client
-type Manager struct {
-	cookieName  string
-	lock        sync.Mutex
-	provider    Provider
-	maxlifetime int64
-}
-
-// NewManager - returns a Cookie manager, ready to use or an error
-func NewManager(provideName, cookieName string, maxlifetime int64) (*Manager, error) {
-	if provider, ok := provides[provideName]; ok {
-		m := &Manager{
-			provider:    provider,
-			cookieName:  cookieName,
-			maxlifetime: maxlifetime,
-		}
-		return m, nil
-	}
-	return nil, fmt.Errorf("session: unknown provide %q", provideName)
-}
-
-// Provider - interface our cookie manager calls to manage lifetimes
-type Provider interface {
-	Init(sid string) (Session, error)
-	Read(sid string) (Session, error)
-	Destroy(sid string) error
-	GC(maxLifeTime int64)
-}
-
-// Session - a client connection
-type Session interface {
-	Set(key, value interface{}) error
-	Get(key interface{}) interface{}
-	Delete(key interface{}) error
-	ID() string
-}
-
-// Register - Add a provider to our stack (e.g., Default)
-func Register(name string, provider Provider) {
-	if provider == nil {
-		log.Fatal("session: Register provider is nil")
-	}
-	if _, ok := provides[name]; !ok {
-		provides[name] = provider
-		return
-	}
-	log.Fatal("session: Register called twice for provider " + name)
-}
-
-// Destroy - Call provider Destroy
-func (manager *Manager) Destroy(w http.ResponseWriter, r *http.Request) {
-	cookie, err := r.Cookie(manager.cookieName)
-	if err != nil || cookie.Value == "" {
-		return
-	}
-	manager.lock.Lock()
-	defer manager.lock.Unlock()
-	manager.provider.Destroy(cookie.Value)
-	expiration := time.Now()
-	c := http.Cookie{
-		Name:     manager.cookieName,
-		Path:     "/",
-		HttpOnly: true,
-		Expires:  expiration,
-		MaxAge:   -1,
-	}
-	http.SetCookie(w, &c)
-}
-
-// Start - Call provider Start
-func (manager *Manager) Start(w http.ResponseWriter, r *http.Request) (session Session) {
-	manager.lock.Lock()
-	defer manager.lock.Unlock()
-	cookie, err := r.Cookie(manager.cookieName)
-	if err != nil || cookie.Value == "" {
-		sid := manager.sessionID()
-		session, _ = manager.provider.Init(sid)
-		cookie := http.Cookie{
-			Name:     manager.cookieName,
-			Value:    url.QueryEscape(sid),
-			Path:     "/",
-			HttpOnly: true,
-			MaxAge:   int(manager.maxlifetime),
-		}
-		http.SetCookie(w, &cookie)
-		return
-	}
-	sid, _ := url.QueryUnescape(cookie.Value)
-	session, _ = manager.provider.Read(sid)
-	return
-}
-
-// GC - call all providers GC
-func (manager *Manager) GC() {
-	manager.lock.Lock()
-	defer manager.lock.Unlock()
-	manager.provider.GC(manager.maxlifetime)
-	time.AfterFunc(30*time.Second, func() { manager.GC() })
-}
-
-func (manager *Manager) sessionID() string {
-	u, err := uuid.NewRandom()
-	if err != nil {
-		log.Fatalf("Unable to generate UUID %q", err)
-	}
-	return u.String()
-}
--- a/transactions/symptoms.go
+++ /dev/null
@@ -1,7 +1,0 @@
-package transactions
-
-// SendEmail - Run on hook from completed payment
-func SendEmail(id string) {
-	// TODO(halfwit) after receipt of payment on the temp wallet, Doctor receives invoice and client receives symptoms link
-	// This is not done through messages at all!
-}