diff --git a/data/employees.csv b/data/employees.csv
new file mode 100644
index 0000000..eaf2e4b
--- /dev/null
+++ b/data/employees.csv
@@ -0,0 +1,46 @@
+id,first,last,position,status,children,hired
+52,John,Barnett,Scheduling,Married,1,3/6/1963
+2,John,Bigbooté,Executive Vice President,Single,0,10/31/1938
+13,John,Camp,Human Resources,Single,0,6/12/1985
+14,John,Careful Walker,Accounting,Single,0,4/30/1990
+15,John,Chief Crier,"VP, Public Relations",Married,2,4/2/1980
+16,John,Cooper,Storage Acquisition,Single,0,8/15/1984
+17,John,Coyote,Medical Research,Married,6,1/1/1970
+18,John,Edwards,Public Relations,Divorced,2,8/15/1984
+19,John,Fat Eating,Craft Services,Single,0,8/15/1984
+20,John,Fish,Marine R&D,Divorced,12,10/31/1938
+21,John,Fledgling,Human Resources,Married,2,7/4/1976
+22,John,Gomez,"VP, Sales",Married,1,8/15/1984
+23,John,Grim,Actuary,Married,1.8,9/9/1970
+24,John,Guardian,Optical Systems Engineer,Single,0,6/9/1980
+25,John,Icicle Boy,Refrigeration R&D,Single,0,2/6/1939
+404,John,Jones,Government Relations,Married,3,8/15/1984
+27,John,Joseph,Government Relations,Married,2,10/31/1938
+28,John,Kim Chi,Craft Services,Married,2,7/24/1990
+29,John,Lee,Accounting,Single,0,12/14/1988
+30,John,Littlejohn,Staff Parliamentarian,Divorced,0,10/31/1938
+31,John,Many Jars,Storage Acquisition Lead,Married,3,1/8/1960
+666,John,Milton,Chief Counsel,Single,2,6/6/1966
+32,John,Mud Head,Apian Research Lead,Married,7,1/2/1956
+33,John,Nephew,Temporal Paradox Resolution,Widowed,0,1/20/1474
+34,John,Nolan,Custodian,Married,2,10/31/1938
+35,John,O'Connor,Temporal Paradox Resolution,Widowed,1,5/15/2022
+37,John,Omar,Imports & Exports,Single,0,9/9/1963
+38,John,Parrot,Computer Design Specialist,Married,1,10/1/1970
+39,John,Rajeesh,Human Resources,Divorced,1,6/12/1982
+11,John,Ready to Fly,Aerial R&D,Married,1,7/4/1976
+40,John,Repeat Dance,Sales,Married,3,6/8/1949
+50,John,Roberts,Counsel,Married,0,4/1/1962
+51,John,Scott,Administration,Single,1,10/31/1938
+59,John,Shaw,Administration,Single,0,8/15/1984
+3,John,Small Berries,Orbital Ergonomitrics Team Leader,Married,3,10/17/1948
+4,John,Starbird,Orbital Ergonomitrics,Married,2,10/18/1948
+5,John,Take Cover,Security Administrator,Divorced,0,2/15/2019
+6,John,Thorny Stick,Sales,Married,0,8/15/1984
+7,John,Turk,System Administrator,Engaged,0,11/3/1986
+8,John,Two Horns,Paralegal,Married,0,8/15/1984
+9,John,Web,IT Support,Married,1,6/8/1949
+1,John,Whorfin,CEO / Lord,Single,0,10/31/1938
+99,John,Wood,Sales,Married,1,8/12/1948
+100,John,Wright,Orbital Mechanics Supervisor,Married,2,10/4/1985
+101,John,Ya Ya,Computer Design Specialist,Married,0,10/31/1938
diff --git a/scrapple/__init__.py b/scrapple/__init__.py
new file mode 100644
index 0000000..84cbbb7
--- /dev/null
+++ b/scrapple/__init__.py
@@ -0,0 +1,17 @@
+from flask import Flask, render_template
+
+app = Flask(__name__)
+
+# common routes
+@app.route("/")
+def index():
+ return render_template("index.html")
+
+
+@app.route("/about")
+def about():
+ return render_template("about.html")
+
+
+from . import parks
+from . import yoyodyne
diff --git a/app.py b/scrapple/parks.py
similarity index 68%
rename from app.py
rename to scrapple/parks.py
index 586ecf2..e9a99f9 100644
--- a/app.py
+++ b/scrapple/parks.py
@@ -1,28 +1,17 @@
import json
import math
-from flask import Flask, render_template, abort, request
+from . import app
+from flask import render_template, abort, request
-app = Flask(__name__)
-
-_data = {}
+_parks = {}
def parks():
- global _data
- if not _data:
+ global _parks
+ if not _parks:
with open("data/parks.json") as f:
- _data = {int(p["id"]): p for p in json.load(f)}
- return _data
-
-
-@app.route("/")
-def index():
- return render_template("index.html")
-
-
-@app.route("/about")
-def about():
- return render_template("about.html")
+ _parks = {int(p["id"]): p for p in json.load(f)}
+ return _parks
@app.route("/parks")
diff --git a/templates/about.html b/scrapple/templates/about.html
similarity index 100%
rename from templates/about.html
rename to scrapple/templates/about.html
diff --git a/scrapple/templates/awards.html b/scrapple/templates/awards.html
new file mode 100644
index 0000000..f7a5b37
--- /dev/null
+++ b/scrapple/templates/awards.html
@@ -0,0 +1,26 @@
+{% extends "base.html" %}
+
+{% block base %}
+
+
Yoyodyne Propulsion Systems Awards
+
+
+
+ {% for award in awards %}
+
+
+
{{ award.name }} {{ award.year }}
+
+ - For
-
+
- {{ award.for }}
+ - Awarded To
+ - {{ award.to }}
+
+
+
+ {% endfor %}
+
+
+
+
+{% endblock %}
diff --git a/templates/base.html b/scrapple/templates/base.html
similarity index 100%
rename from templates/base.html
rename to scrapple/templates/base.html
diff --git a/templates/index.html b/scrapple/templates/index.html
similarity index 100%
rename from templates/index.html
rename to scrapple/templates/index.html
diff --git a/templates/park_detail.html b/scrapple/templates/park_detail.html
similarity index 100%
rename from templates/park_detail.html
rename to scrapple/templates/park_detail.html
diff --git a/templates/parks.html b/scrapple/templates/parks.html
similarity index 100%
rename from templates/parks.html
rename to scrapple/templates/parks.html
diff --git a/scrapple/templates/staff.html b/scrapple/templates/staff.html
new file mode 100644
index 0000000..485661f
--- /dev/null
+++ b/scrapple/templates/staff.html
@@ -0,0 +1,40 @@
+{% extends "base.html" %}
+
+{% block base %}
+
+
Yoyodyne Propulsion Systems Staff Roster
+
+
+
+
+ First Name |
+ Last Name |
+ Position Name |
+ |
+
+
+
+ {% for e in employees %}
+
+ {{ e.first }} |
+ {{ e.last }} |
+ {{ e.position }} |
+ Details |
+
+ {% endfor %}
+
+
+
+ {% if prev_page %}
+
« Previous
+ {% else %}
+
+
+ {% endif %}
+ {% if next_page %}
+
Next »
+ {% endif %}
+
+
+
+{% endblock %}
diff --git a/scrapple/templates/staff_detail.html b/scrapple/templates/staff_detail.html
new file mode 100644
index 0000000..6bb6969
--- /dev/null
+++ b/scrapple/templates/staff_detail.html
@@ -0,0 +1,19 @@
+{% extends "base.html" %}
+
+{% block base %}
+
+
Employee Details for {{ employee.first }} {{ employee.last }}
+
+
+ - Position
+ - {{ employee.position }}
+ - Marital Status
+ - {{ employee.status }}
+ - Number of Children
+ - {{ employee.children }}
+ - Hired
+ - {{ employee.hired }}
+
+
+
+{% endblock %}
diff --git a/scrapple/yoyodyne.py b/scrapple/yoyodyne.py
new file mode 100644
index 0000000..2baac2f
--- /dev/null
+++ b/scrapple/yoyodyne.py
@@ -0,0 +1,109 @@
+import csv
+import math
+from . import app
+from flask import render_template, abort, request
+
+
+_employees = {}
+
+
+def employees():
+ # thanks to http://www.figmentfly.com/bb/badguys3.html for names
+ global _employees
+ if not _employees:
+ with open("data/employees.csv") as f:
+ _employees = {e["id"]: e for e in csv.DictReader(f)}
+ return _employees
+
+
+@app.route("/awards")
+def awards():
+ award_data = [
+ {
+ "name": "Nobel Prize in Physics",
+ "year": "1934",
+ "for": "Discovery of the 8th Dimension",
+ "to": "John Whorfin",
+ },
+ {
+ "name": "Cousteau Society Award",
+ "year": "1989",
+ "for": "Uses of Cephalopod Intelligence",
+ "to": "John Fish",
+ },
+ {
+ "name": "Best Supporting Actor",
+ "year": "1985",
+ "for": "John Lithgow Biopic",
+ "to": "John Whorfin",
+ },
+ {
+ "name": "Nobel Prize in Physics",
+ "year": "2986",
+ "for": "Temporal Paradox Resolution",
+ "to": "John O'Connor",
+ },
+ {
+ "name": "Paralegal of the Year",
+ "year": "1999",
+ "for": "Paralegal Activity",
+ "to": "John Two Horns",
+ },
+ {
+ "name": "ACM Award",
+ "year": "1986",
+ "for": "Innovations in User Interface",
+ "to": "John Ya Ya",
+ },
+ {
+ "name": "2nd Place, Most Jars Category",
+ "year": "1987",
+ "for": "Jars",
+ "to": "John Many Jars",
+ },
+ {
+ "name": "Album of the Year",
+ "year": "1997",
+ "for": "Space Coyote",
+ "to": "John Coyote",
+ },
+ {
+ "name": "Most Creative Loophole",
+ "year": "1985",
+ "for": "Innovation in Interdimensional Tax Shelters",
+ "to": "John Lee",
+ },
+ ]
+ return render_template("awards.html", awards=award_data)
+
+
+@app.route("/staff")
+def staff():
+ page = int(request.args.get("page", 1))
+ per_page = 10
+ total_items = len(employees())
+ max_page = math.ceil(total_items / per_page)
+ print(max_page)
+ if page < 1 or page > max_page:
+ abort(404)
+ page_employees = list(employees().values())[(page - 1) * per_page : page * per_page]
+ return render_template(
+ "staff.html",
+ employees=page_employees,
+ page=page,
+ prev_page=page - 1,
+ next_page=page + 1 if page < max_page else None,
+ )
+
+
+@app.route("/staff/")
+def staff_detail(id_):
+ if id_ == "404":
+ abort(
+ 404,
+ "This page intentionally left blank. (No really! This is an intentional error for demonstration purposes.)",
+ )
+ if employee := employees().get(id_):
+ return render_template("staff_detail.html", employee=employee)
+ else:
+ abort(404)