diff --git a/.gitignore b/.gitignore
index 076a415d..a2cd91bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,43 +1,43 @@
-# Don't track content of these folders
-config.ini
-*.ini
-# Compiled source #
-###################
-*.com
-*.class
-*.dll
-*.exe
-*.o
-*.so
-
-# Packages #
-############
-# it's better to unpack these files and commit the raw source
-# git has its own built in compression methods
-*.7z
-*.dmg
-*.gz
-*.iso
-*.jar
-*.rar
-*.tar
-*.zip
-
-# OS generated files #
-######################
-.DS_Store
-.DS_Store?
-._*
-.Spotlight-V100
-.Trashes
-ehthumbs.db
-Thumbs.db
-
-
-**/.idea/
-**/__pycache__/
-*.cpython-36.pyc
-*.pyc
-
-run.sh
-flomenv/
+# Don't track content of these folders
+config.ini
+*.ini
+# Compiled source #
+###################
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.so
+
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+
+# OS generated files #
+######################
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+
+**/.idea/
+**/__pycache__/
+*.cpython-36.pyc
+*.pyc
+
+run.sh
+flomenv/
diff --git a/LICENSE b/LICENSE
index 406d5ac0..7e9721ac 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2019 FLOM
+Copyright (c) 2019 flomv2
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Logo-Ideas/FlomLogo1.jpg b/Logo-Ideas/FlomLogo1.jpg
new file mode 100644
index 00000000..0a003123
Binary files /dev/null and b/Logo-Ideas/FlomLogo1.jpg differ
diff --git a/Logo-Ideas/FlomLogo2.jpg b/Logo-Ideas/FlomLogo2.jpg
new file mode 100644
index 00000000..1dbae670
Binary files /dev/null and b/Logo-Ideas/FlomLogo2.jpg differ
diff --git a/Logo-Ideas/README.md b/Logo-Ideas/README.md
new file mode 100644
index 00000000..085a9e60
--- /dev/null
+++ b/Logo-Ideas/README.md
@@ -0,0 +1,2 @@
+This directory contains posisble logo ideas :)
+I can change/add color and add any redesigns.
diff --git a/Logo-Ideas/logo idea0.png b/Logo-Ideas/logo idea0.png
new file mode 100644
index 00000000..d4e304d2
Binary files /dev/null and b/Logo-Ideas/logo idea0.png differ
diff --git a/Logo-Ideas/logo idea1.png b/Logo-Ideas/logo idea1.png
new file mode 100644
index 00000000..1c5583e0
Binary files /dev/null and b/Logo-Ideas/logo idea1.png differ
diff --git a/Logo-Ideas/logo idea2.png b/Logo-Ideas/logo idea2.png
new file mode 100644
index 00000000..d3e1e298
Binary files /dev/null and b/Logo-Ideas/logo idea2.png differ
diff --git a/Logo-Ideas/logo idea4.png b/Logo-Ideas/logo idea4.png
new file mode 100644
index 00000000..e4987155
Binary files /dev/null and b/Logo-Ideas/logo idea4.png differ
diff --git a/Logo-Ideas/logo idea5.png b/Logo-Ideas/logo idea5.png
new file mode 100644
index 00000000..6cab2f12
Binary files /dev/null and b/Logo-Ideas/logo idea5.png differ
diff --git a/Logo-Ideas/logo-idea1.jpg b/Logo-Ideas/logo-idea1.jpg
new file mode 100644
index 00000000..5a7c70ae
Binary files /dev/null and b/Logo-Ideas/logo-idea1.jpg differ
diff --git a/Logo-Ideas/logo-idea2.jpg b/Logo-Ideas/logo-idea2.jpg
new file mode 100644
index 00000000..a8874f11
Binary files /dev/null and b/Logo-Ideas/logo-idea2.jpg differ
diff --git a/Logo-Ideas/logo-idea3.jpg b/Logo-Ideas/logo-idea3.jpg
new file mode 100644
index 00000000..b26fb1c0
Binary files /dev/null and b/Logo-Ideas/logo-idea3.jpg differ
diff --git a/Logo-Ideas/logo-idea4.jpg b/Logo-Ideas/logo-idea4.jpg
new file mode 100644
index 00000000..de248142
Binary files /dev/null and b/Logo-Ideas/logo-idea4.jpg differ
diff --git a/Media/logo.jpg b/Media/logo.jpg
new file mode 100644
index 00000000..ebfc8f58
Binary files /dev/null and b/Media/logo.jpg differ
diff --git a/README.md b/README.md
index 7fa9f612..8a59b837 100644
--- a/README.md
+++ b/README.md
@@ -2,55 +2,49 @@
### Folsom Library Occupancy Manager
-http://www.flom.ml
+FLOM is a web application created by a group of RPI students that allows the students and library staff at RPI to visualize the occupancy and gather usage statistics of the Folsom Library Occupancy Monitor.
-Develop an embedded system that allows students to sign into a website with their RCS ID to check what study rooms in the library are occupied and which are not. This will increase students' efficiency when studying.
+## Getting Started
+To get started all you need to do is clone the repository onto your local machine
+by typing ```git clone https://github.com/flomv2/FLOM.git``` in your terminal.
-## Build Instructions
+Before you can run the web application, you will need to complete the Django install tutorial that is located on our GitHub in the Tutorials folder.
-Clone the URI and run the `manage.py` file located in the \_software directory.
+Please refer to this [Django tutorial](https://docs.djangoproject.com/en/2.2/intro/tutorial01/) or simply the
+[Django 2.2 documentation](https://docs.djangoproject.com/en/2.2/) for information about using our framework. Django provides a robust templating framework for HTML (that means please use it).
-`python manage.py runserver`
+## Build Instructions
-Your local build will require access to a database. Our implementation uses [Postgres](https://www.postgresql.org/) and you can create a `config.ini` file with data to your local database. Alternatively, we can set you up with access to our AWS database if you want to join our team.
+Once the URI is cloned, you can then run Django by moving into the WebApp directory in flom and running ```python3 manage.py runserver``` . This will start the web application on your localhost. In later versions you may need to install and setup Postgresql database which we will have tutorials on.
-You may need to download these python libraries (if you don't already have them).
+## Code of Conduct and Style Guidelines
-```pip install Django``` \
-```pip install psycopg2``` \
-```pip install memcache```
+Our developers pride ourselves on writing beautiful and efficient code. Contributers should follow standard good style practices such as: useful commenting, proper indentation, and portability. Our Web Application directory looks like this
-## Code of Conduct and Style Guidelines
+ `Tutorials/` - Tutorials on how to set up different aspcts of the flom project
+ `WebApp/` - Main source code in which apps of each web page are created and urls are connected
+ `License.md` - MIT License
+ `README.md` - This file
-Our developers pride ourselves on writing beautiful and efficient code. Contributers should follow standard good style practices such as
-useful commenting, proper indentation, and portability. Our software app directory looks like this
-
- `database/` - Database objects, queries, and all things postgres
- `flom/` - Main settings and urls
- `library_monitor/` - Front end styles and templates
- `static/` - Main scripts and styles
- `templates/` - Main template files
- `config.ini` - Required metadata for database connection
- `manage.py` - Managing file from Django
-
-Please refer to this [Django tutorial](https://docs.djangoproject.com/en/2.2/intro/tutorial01/) or simply the
-[Django 2.2 documentation](https://docs.djangoproject.com/en/2.2/) for information about using our framework. Django provides a robust templating framework for HTML (that means please use it).
+## Website/Communication
+https://rcos.io/projects/flomv2/flom/profile
+Contact any of the contributors on this page and we can add you to our Mattermost chat! This is also where you can find our blog.
## Git Branching Model
-When making a new feature or a bug fix, please make a new branch from **Dev** (short for develop). On your command line, run
+When making a new feature or a bug fix, please make a new branch from **Master** (or branch you are trying to modify). On your command line, run
-`git checkout dev` \
+`git checkout **(original branch name)**` \
`git branch [new branch name]` \
-`git checkout [new branch name]`
+`git checkout [new branch name]`
-Branch names should be concise and self-explanatory. Please make your branch names lowercase and use hyphens (-) for spaces. You don't need to prepend your branch name with "dev" or include other details such as your name. For example, a feature branch for updating the about page UI might be called `about-styles` or `about-page-ui`.
+Branch names should be concise and self-explanatory. Please make your branch names lowercase and use hyphens (-) for spaces. You don't need to prepend your branch name with or include other details such as your name. For example, a feature branch for updating the about page UI might be called `about-styles` or `about-page-ui`.
-When you have changes to your local code base in your new branch, commit push them with
+When you have changes to your local code base in your new branch, commit push them with
`git commit -m [Commit message]` \
-`git push`
+`git push`
-Commit messages should be concise and self-explanatory, just like branch names.
+Commit messages should be concise and self-explanatory, just like branch names.
-Once your have completed your feature or fixed you bug, please perform a **Pull Request** into dev, even if you are an admin. Pull requests provide a more readable commit log, highlighting major features and changes. On the Github repository website, click new pull request and select `"dev" <- "your branch name"`. This allows an admin to approve your changes before they are live on the develop branch.
+Once your have completed your feature or fixed you bug, please perform a **Pull Request** into master, even if you are an admin. Pull requests provide a more readable commit log, highlighting major features and changes. On the Github repository website, click new pull request and select `"master" <- "your branch name"`. This requires an admin to approve your changes before they are live on the develop branch.
diff --git a/Test-Scripts/testThread.py b/Test-Scripts/testThread.py
new file mode 100644
index 00000000..8d723cc1
--- /dev/null
+++ b/Test-Scripts/testThread.py
@@ -0,0 +1,24 @@
+import threading
+import time
+
+
+def threadf(name):
+ print("Thread %s: starting thread",name)
+ x = 0
+ while(1):
+ time.sleep(1)
+ s = "Thread " + str(x)
+ print(s)
+ x = x + 1
+
+if __name__ == "__main__":
+ print("Starting Program")
+ x = threading.Thread(target=threadf, args=(1,))
+ x.start()
+ y = 0
+ while(1):
+ time.sleep(2)
+ s = "Main: " + str(y)
+ print(s)
+ y = y + 1
+
diff --git a/Test-Scripts/thr.py b/Test-Scripts/thr.py
new file mode 100644
index 00000000..3f6c47ec
--- /dev/null
+++ b/Test-Scripts/thr.py
@@ -0,0 +1,21 @@
+import threading
+import time
+import datetime
+
+def threadf(name):
+ hours = []
+ while(True):
+ time.sleep(15)
+ now = datetime.datetime.now()
+ if (len(hours) == 0):
+ hours.append(now)
+ print(now.hour)
+ elif (now.hour != hours[-1].hour):
+ hours.append(now)
+ print(now.hour)
+
+
+if __name__ == "__main__":
+ print("Starting Program")
+ x = threading.Thread(target=threadf, args=(1,))
+ x.start()
\ No newline at end of file
diff --git a/Tutorials/DjangoInstallGuide.md b/Tutorials/DjangoInstallGuide.md
new file mode 100644
index 00000000..c81a674a
--- /dev/null
+++ b/Tutorials/DjangoInstallGuide.md
@@ -0,0 +1,105 @@
+# Installing Python and Django
+1. Install Python and Pip
+ * We have to first update the local APT repository.
+````shell
+$ sudo apt-get update && sudo apt-get -y upgrade
+````
+2. Install Python 3
+````shell
+$ sudo apt-get install python3
+````
+3. Verify that Python was installed correctly.
+````shell
+$ python3 -V
+````
+4. Install pip which is used to install packages from PyPi (Python's package repository)
+```` shell
+$ sudo apt-get install -y python3-pip
+````
+5. Verify that pip was intalled
+````shell
+$ pip3 -V
+````
+6. Install virtualenv
+ * This is a virtual environment where you can install software and python packages in a contained development space.
+ ````shell
+ $ pip3 install virtualenv
+ ````
+ 7. Verify that virtualenv is installed
+ ````shell
+ $ virtualenv --version
+ ````
+ 8. Install Django
+ 1. Make a new directory and then switch into that new directory.
+ ````shell
+ $ mkdir django-apps
+ $ cd django-apps
+ ````
+ 2. While inside the django-apps directory create a new virtual environment which we called env.
+ ````shell
+ $ virtualenv env
+ ````
+ 3. Now activate the virtual environment
+ ````shell
+ $ . env/bin/activate
+ ````
+ You can tell that it is activated if you see something similar to this:
+ ````shell
+ (env) sylvee@DESKTOP-RFPF6M7:
+ ````
+ 4. Now intall the Django package with pip3
+ ````shell
+ $ pip3 install django
+ ````
+ 5. Verify that Django installed
+ ````shell
+ $ django-admin --version
+ ````
+
+# Django Test Project
+
+1. Genrating the intial setup code if this is your first time using Django.
+ ````shell
+ $ django-admin startproject mysite
+ ````
+
+These files are:
+* The outer `mysite/` root directory is just a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like.
+* - `manage.py`: A command-line utility that lets you interact with this Django project in various ways. You can read all the details about `manage.py` in [django-admin and manage.py](https://docs.djangoproject.com/en/2.2/ref/django-admin/).
+* - The inner `mysite/` directory is the actual Python package for your project. Its name is the Python package name you’ll need to use to import anything inside it (e.g. `mysite.urls`).
+* - `mysite/__init__.py`: An empty file that tells Python that this directory should be considered a Python package. If you’re a Python beginner, read [more about packages](https://docs.python.org/3/tutorial/modules.html#tut-packages "(in Python v3.7)") in the official Python docs.
+* - `mysite/settings.py`: Settings/configuration for this Django project. [Django settings](https://docs.djangoproject.com/en/2.2/topics/settings/) will tell you all about how settings work.
+* - `mysite/urls.py`: The URL declarations for this Django project; a “table of contents” of your Django-powered site. You can read more about URLs in [URL dispatcher](https://docs.djangoproject.com/en/2.2/topics/http/urls/).
+* - `mysite/wsgi.py`: An entry-point for WSGI-compatible web servers to serve your project. See [How to deploy with WSGI](https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/) for more details.
+2. Verify that the project works by running the devserver.
+````shell
+$ python manage.py runserver
+````
+
+You should see something like this. Note for now ignore the erros about unapplied migrations.
+
+````shell
+Watching for file changes with StatReloader
+Performing system checks...
+
+System check identified no issues (0 silenced).
+
+You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
+Run 'python manage.py migrate' to apply them.
+
+July 16, 2019 - 17:07:09
+Django version 2.2.3, using settings 'mysite.settings'
+Starting development server at http://127.0.0.1:8000/
+Quit the server with CONTROL-C.
+ ````
+ 3. Visit http://127.0.0.1:8000/ and you should see a rocket.
+ 4. For more in depth tutorial checkout [Django's Tutorial](https://docs.djangoproject.com/en/2.2/intro/tutorial01/)
+ 5. Now you are ready to begin development of your project.
+
+
+
+
+
+
+
+
diff --git a/Tutorials/HTMLCheatSheet.md b/Tutorials/HTMLCheatSheet.md
new file mode 100644
index 00000000..f81db3f0
--- /dev/null
+++ b/Tutorials/HTMLCheatSheet.md
@@ -0,0 +1,163 @@
+## What is HTML?
+HTML is short for "HyperText Markup Language." It simply means it is a language for describing web-pages using ordinary text.
+## HTML Files
+Every web page is an HTML file. Each HTML file is just like a plain-text file but with a ```.html``` extension instead of ```.txt```
+## HTML Tags
+HTML tags are hidden *keywords* within a web page that define how your web browser must format and display the content.
+Most tags have two parts, an opening and a closing part. For example, `````` is the opening tag and `````` is the closing tag. Note that the closing tag has the same text as the opening tag, but has an additional forward-slash(/) character.
+There are some tags that are an exception to this rule, where a closing tag is not required. The ``` ``` tag for showing images is one example of this.
+Each HTML file must have the essential tags for it to be valid, so that web browsers can understand it and display it correctly. The essential tags are:
+- ``````
+- ```
```
+- ``` ```
+- ``````
+#### Definition - ``` ```
+This basically defines the document as web page. It also identifies the beginning and end of the HTML document. All other tags must fall between the html tags.
+#### Header - ``` ```
+The header file contains information about the document that will not appear on the actual page, such as the title of the document, the author, which stylesheet to use and also meta tags.
+#### Title - ``` ```
+The title tag defines the title that will appear in the title bar of your web browser. The title must appear between the head tags.
+#### Body - ``` ```
+The body tags contain all the information and other visible content on the page. All your images, links, and plain text must go between the `````` and `````` tags.
+#### Example: Basic HTML Structure
+```
+
+
+ My Page Title
+
+
+ This is where all my web page content goes!
+
+
+```
+## Tag Attributes
+Attributes allow you to customize a tag, and are defined within the opening tag, for example:
+``` ```...``````
+## Common Tags
+| HTML | Description |
+| ----------------------------------------- |:----------------------------------------------------------:|
+| ``` heading ``` | heading (h1 for largest to h6 for smallest) |
+| ``` paragraph
``` | Paragraph of Text |
+| ``` bold ``` | Make text between tags bold |
+| ``` italic ``` | Make text between tags italic |
+|``` link name ``` | Create a link to another page or website |
+|```...
``` | Divide up page content into sections, and applyting styles |
+|``` ``` | Show an image |
+|`````` | Unordered, bullet-point list |
+|``` ``` | Line Break (force a new line) |
+|``` red ``` | Use CSS style to change text color |
+
+## Text Formatting
+| HTML | Description |
+| --------------------------------- | :-------------------------------------------------- |
+| ```... ``` | Heading (?=1 for largest to 6 for smallest, e.g. h1 |
+|```... ``` | Bold Text |
+|```... ``` | Italic Text |
+|```... ``` | Underline text |
+|```... ``` | Strikeout Text |
+|```... ``` | Superscript - Smaller text placed above normal text |
+|```... ``` | Subscript - Smaller text placed below normal text |
+|```... ``` | Typewriter text |
+|```... ``` | Pre-formatted Text |
+|```... ``` | Text Block Quote |
+|```... ``` | Strong- Shown as Bold in most browsers |
+|```... ``` | Emphasis - Shown as Italics in most browsers |
+|```... ``` | Font tag obsolete, use CSS (see below) |
+
+## Section Divisions
+| HTML | Description |
+| --------------------------- | :---------------------------------------- |
+| ```...
``` | Division or Section of Page Content |
+|```... ``` | Section of text within other content |
+|```...
``` | Paragraph of text |
+|``` ``` | Line Break |
+|```... ``` | Line Break |
+|``` ``` | Basic horizontal Line |
+| hr Tag Attributes: | |
+| ``` size="?"``` | Line Thickness in pixels |
+| ``` width="?"``` | Line Width in pixels |
+| ``` width="??%"``` | Line Width as a percentage |
+| ``` color="#??????"``` | Line Color (see below) |
+| ``` align="?"``` | Horizontal Alignment: left, center, right |
+| ``` noshade``` | No 3D cut-out |
+
+## Images
+| HTML | Description |
+| ------------------------------ | :---------------------------------------- |
+| ``` ``` | Basic Image |
+| img Tag Attributes: | |
+| ``` src="url"``` | URL or filename of image (required!) |
+| ``` alt="text"``` | Alternate Text (required!) |
+| ``` align="?"``` | Image alignment within surrounding text |
+| ``` width="??"``` | Image width (in pixels or %) |
+| ``` height="??"``` | Image height (in pixels or %) |
+| ``` border="??"``` | Border thickness (in pixels) |
+| ``` vpace="??"``` | Space above and below image (in pixels) |
+| ``` hspace="??"``` | Space on either side of image (in pixels) |
+
+## Linking Tags
+| HTML | Description |
+| ---------------------------------- | :---------------------------------------------------------------- |
+|``` link text ``` | Basic Link |
+| a Tag Attributes: | |
+| ```href="url"``` | Location (url) of page to link to |
+| ```name="??"``` | Name of link (name of anchor, or name of bookmark) |
+| ```target="?"``` | Link target location: _self, _blank, _top, _parent. |
+| ```href="url#bookmark"``` | Link to a bookmark (defined with name attribute). |
+| ``` href="mailto:email"``` | Link which initiates an email (dependent on user's email client). |
+
+## Lists
+| HTML | Description |
+| --------------------- | :----------------------------------------------------- |
+| ```... ``` | Ordered List |
+| `````` | Un-ordered List |
+| ```... ``` | List Item (within ordered or unordered) |
+| ``` ``` | Ordered list type A, a, I, i, l |
+| `````` | Ordered list starting value |
+| ``` ``` | Unordered list bullet type: disc, circle, square |
+| `````` | List Item Value (changes current and subsequent items) |
+| ``` ``` | List Item Type (changes only current item) |
+| ```... ``` | Definition List |
+| ```... ``` | Term or phrase being defined |
+| ```... ``` | Detailed Definition of Term |
+
+## Special Characters
+| HTML | Descripion |
+| ------------- | :--------------------------- |
+| ```<``` | < Less than symbol |
+| ```>``` | > Greater than symbol |
+| ```&``` | & Ampersand, or 'and' sign |
+| ```"``` | " Quotation mark |
+| ```©``` | Copyright Symbol |
+| ```™``` | Trademark Symbol |
+| ``` ``` | A Space (non-breaking space) |
+
+## Miscellaneous Tags
+| HTML | Description |
+| ------------------ | :------------------------------ |
+| `````` | Comment within HTML source code |
+
+## Body Background & Colors
+| HTML | Desciption |
+| -------------------------- | :------------------------------------------------------ |
+| body Tag Attributes: | |
+| ```background = "url"``` | Background Image |
+| ```bgcolor = "#??????"``` | Background Color |
+| ``` text="#??????"``` | Document Text Color |
+| ```link="#??????"``` | Link Color |
+| ```vlink="#??????"``` | Visited Link Color |
+| ```alink="#??????"``` | Active Link Color |
+| ```bgproperties="fixed"``` | Background Properties -"Fixed"= non-scrolling watermark |
+| ```leftmargin="?"``` | Side Margin Size in Pixels (Internet Explorer) |
+| ```topmargin="?"``` | Top Margin Size in Pixels (Internet Explorer) |
+
+
+
+
+
+
+###### Resources:
+###### http://www.simplehtmlguide.com/whatishtml.php
+###### http://www.simplehtmlguide.com/basics.php
+###### http://www.simplehtmlguide.com/essential.php
+###### http://www.simplehtmlguide.com/cheatsheet.php
diff --git a/Tutorials/Makefile b/Tutorials/Makefile
new file mode 100644
index 00000000..6ace54a2
--- /dev/null
+++ b/Tutorials/Makefile
@@ -0,0 +1,16 @@
+.PHONY install
+install
+ sudo apt-get update
+ sudo apt-get -y upgrade
+ sudo apt-get install python3
+ python3 -V
+ sudo apt-get install -y python3-pip
+ pip3 -V
+ pip3 install virtualenv
+ virtualenv --version
+ mkdir django-apps
+ cd django-apps
+ virtualenv env
+ . envbinactivate
+ pip3 install django
+ django-admin --version
diff --git a/Tutorials/PostgresInstallGuide.md b/Tutorials/PostgresInstallGuide.md
new file mode 100644
index 00000000..f367a2a1
--- /dev/null
+++ b/Tutorials/PostgresInstallGuide.md
@@ -0,0 +1,100 @@
+# Installing and Using PostgreSQL with Django
+This guide assumes that you've already installed Python3 to your machine and set up a Django application as detailed in our [Django Install Guide](./DjangoInstallGuide.md).
+
+## Installing PostgreSQL
+This guide will teach you how to install PostgreSQL for Ubuntu. If you're running on a different operating system, follow the PostgreSQL install guides available [here](https://www.postgresql.org/download/).
+
+1. Set up your machine to add the PostgreSQL repository. Ubuntu repositories contain snapshot versions of PostgreSQL, so for the latest version setting up an additional repository is required.
+```bash
+$ sudo apt-get install wget ca-certificates
+$ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
+$ sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" >> /etc/apt/sources.list.d/pgdg.list'
+```
+2. Install the PostgreSQL packages
+```bash
+$ sudo apt-get update
+$ sudo apt-get install postgresql postgresql-contrib
+```
+
+## Setting up a Database
+Once you've installed PostgreSQL, you'll need to set up a database in order to link it with Django. For our purposes we'll call the database 'flom' for use with the FLOM project, but if you're setting up a database for another project feel free to change the name.
+ 1. Log into the `postgres` user that was created during installation of PostgreSQL. You need to do this in order to perform administrative tasks on your databases.
+```bash
+$ sudo su - postgres
+```
+2. Once logged in as the `postgres` user, log into a PostgreSQL session.
+```bash
+$ psql
+```
+ * You may encounter an error that says:
+ ```bash
+ psql: could not connect to server: No such file or directory
+
+ Is the server running locally and accepting connections on
+ Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
+ ```
+ * This error has to do with the server being misconfigured before it starts. Follow these steps to fix this error.
+ 1. Certify that postgresql service is running, using ```sudo service postgresql start```
+ 2. Run ```pg_lsclusters``` from your terminal.
+
+ The output should be something like:
+
+ ```bash
+ Ver Cluster Port Status Owner Data directory Log file
+ 11 main 5432 down postgres /var/lib/postgresql/11/main /var/log/postgresql/postgresql-11-main.log
+ ```
+ 4. Copy the version and the cluster, and run: ```pg_ctlcluster start ```
+ 5. Now the server should be running and you can verify this by using ```sudo service postgresql start``` again.
+3. Once you've started a PostgreSQL session, you'll need to create a database, a user to interact with that database, and set the default expected values for the user that Django expects.
+```bash
+postgres=# CREATE DATABASE flom;
+postgres=# CREATE USER flom_admin WITH PASSWORD 'password';
+postgres=# ALTER ROLE flom_admin SET client_encoding TO 'utf8';
+postgres=# ALTER ROLE flom_admin SET default_transaction_isolation TO 'read committed';
+postgres=# ALTER ROLE flom_admin SET timezone TO 'UTC';
+postgres=# GRANT ALL PRIVILEGES ON DATABASE flom TO flom_admin;
+```
+4. Exit out of the PostgreSQL session and the `postgres` user shell session and get back into your user shell session.
+```bash
+postgres=# \q
+$ exit
+```
+
+## Linking a PostgreSQL database to a Django application
+At last, link the PostgreSQL database that you created above to your Django application.
+1. Change into your project's working directory and enter the virtual enviornment to install `psycopg2`, a library necessary for PostgreSQL to work with Python.
+```bash
+$ . env/bin/activate
+$ pip3 install psycopg2
+```
+2. Open the `settings.py` module located in the child project directory. Scroll down until you see a section that looks similar to this:
+```python
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+ }
+}
+```
+Change this section to look like the following (change the corresponding information if you changed anything while setting up the databse):
+```python
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.postgresql_psycopg2',
+ 'NAME': 'flom',
+ 'USER': 'flom_admin',
+ 'PASSWORD': 'password',
+ 'HOST': 'localhost',
+ 'PORT': '5432',
+ }
+}
+```
+After making these changes, save and close the `settings.py`.
+
+4. Change into the Django project directory to create and apply any existing migrations to the database.
+```
+$ python3 manage.py makemigrations
+$ python3 manage.py migrate
+```
+
+Congratulations! You have successfully linked a PostgreSQL database to your Django application!
diff --git a/WebApp/README.md b/WebApp/README.md
new file mode 100644
index 00000000..71436451
--- /dev/null
+++ b/WebApp/README.md
@@ -0,0 +1,34 @@
+## Understanding what our WebApp is...
+### What is an App?
+The term "application" describes a Python package that provides some set of features.
+Applications include some combination of models, views, templates, template tags, static files, URLs, middleware, etc.
+Django forces creators to break his/her code into these "apps".
+#### *manage.py*
+This is a container for all of our project's applications.
+Think of the arguments passed to manage.py as subcommands. It is a tool for executing many Django-specific tasks. It is also an extension point where developers can create custom commands that are specific to his/her app.
+### Our "Apps"...
+- *about*: For the *About page* on our website
+- *floor3*: For the *Floor 3 page* on our website
+- *floor4*: For the *Floor 4 page* on our website
+- *stats*: For the *Stats page* on our website
+### Now we will explore the general layout of each of our "Apps"...
+#### *admin.py*
+This file is where we put all of our configuration regarding the Django builtin admin.
+In other words, it is used to display our models in and customize the Django admin pannel
+#### *apps.py*
+This file is used in Django's internal app registry and is mainly used to store metadata. For the most part, we do not modify this.
+#### *__init__.py*
+This file is Python's convention for determining modules. When one tries to run ```import library``` or ```from library import``` Python will search all folders in the Python path. If a folder has an ```__init__.py``` file, Python will also search inside of that folder, otherwise, it is ignored.
+#### *migrations folder*
+Migrations are how Django builds your database. Migrations are Django's way of propagating changes you make to your models (adding a field, deleting a model, etc.) into your database schema. The migration files for each app live in this migrations directory.
+#### *models.py*
+This file is where we store all of our models related to the app. Models are how Django understands our databse and how we want our data stored.
+#### *tests.py*
+This file is for adding unit and integration tests. A test is code one writes to make sure his/her code is running how he/she expected.
+#### *views.py*
+A view is simply a Python function that takes a web request and returns a web response. The views.py file is where we define all of our views related to this app, both Class-Based and Function-Based.
+#### *urls.py*
+This file is used to store app specific mappings of URLs to views.
+For every URL that starts with a blank space in our project, Django will find the corresponding view.
+#### *static & templates folders*
+These folders are simply used to store static files or template files in each of our applications. They are stored into a single location that can easily be served.
diff --git a/_software/database/__init__.py b/WebApp/WebApp/__init__.py
similarity index 100%
rename from _software/database/__init__.py
rename to WebApp/WebApp/__init__.py
diff --git a/_software/flom/settings.py b/WebApp/WebApp/settings.py
similarity index 55%
rename from _software/flom/settings.py
rename to WebApp/WebApp/settings.py
index ecd3a390..5cabd1a7 100644
--- a/_software/flom/settings.py
+++ b/WebApp/WebApp/settings.py
@@ -1,162 +1,157 @@
-"""
-Django settings for flom project.
-
-Generated by 'django-admin startproject' using Django 2.1.5.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/2.1/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/2.1/ref/settings/
-"""
-
-
-import os
-import json
-from django.core.cache import cache
-import ast
-
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-CONFIG_FILE = 'config.ini'
-config = {}
-with open(CONFIG_FILE) as f:
- config = json.load(f)
-
-# Quick-start development settings - unsuitable for production
-# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
-
-# if config['DEVELOPMENT'] == "True":
-# print("IN DEV MODE")
-# from . import sample_data_loader as sdl
-# sdl.create_tables(config['DATABASES']['default'])
-# sdl.insert_occupancy(config['DATABASES']['default'])
-# print('finished sdl')
-
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = config['SECRET_KEY']
-
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
-
-SESSION_COOKIE_HTTPONLY = 'django.contrib.sessions.backends.signed_cookies'
-
-ALLOWED_HOSTS = ['flom.ml','www.flom.ml','localhost','127.0.0.1']
-
-# Application definition
-
-INSTALLED_APPS = [
- 'library_monitor.apps.LibraryMonitorConfig',
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'database'
-]
-
-MIDDLEWARE = [
- 'django.middleware.security.SecurityMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
-]
-
-ROOT_URLCONF = 'flom.urls'
-
-TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [os.path.join(BASE_DIR, 'templates')],
- 'APP_DIRS': True,
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
- ],
- },
- },
-]
-
-WSGI_APPLICATION = 'flom.wsgi.application'
-
-# Database
-# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
-DATABASES = config['DATABASES']
-
-# Password validation
-# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
-
-AUTH_PASSWORD_VALIDATORS = [
- {
- 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
- },
-]
-
-#comment out for local running
-#cache settings
-# CACHES = {
-# 'default': {
-# 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
-# 'LOCATION': '127.0.0.1:11211',
-# }
-# }
-
-# Internationalization
-# https://docs.djangoproject.com/en/2.1/topics/i18n/
-
-LANGUAGE_CODE = 'en-us'
-
-TIME_ZONE = 'America/New_York'
-
-USE_I18N = True
-
-USE_L10N = True
-
-USE_TZ = True
-
-# SESSION_COOKIE_SECURE = True
-# SECURE_SSL_REDIRECT = True
-# CSRF_COOKIE_SECURE = True
-
-
-# Static files (CSS, JavaScript, Images)
-# https://docs.djangoproject.com/en/2.1/howto/static-files/
-
-STATIC_URL = '/static/'
-# print(cache.get('initialized'))
-
-cache.set('SECRET_KEYs', config['SECRET_KEYs'], None)
-cache.set('dev', config['DEVELOPMENT'])
-cache.set('floors', list(config['FLOOR'].keys()), None)
-for floor in config['FLOOR']:
- rooms = config['FLOOR'][floor]
- rooms = ast.literal_eval(rooms)
- cache.set('floor_' + floor, rooms, None)
- for room_id in rooms:
- stats = {"occupied": False, "e_time": None, "last_enter": None,
- "last_leave": None, "dao": None, "dau": None, "floor": floor}
- cache.set(room_id, stats, None)
-
-STATICFILES_DIRS = [
- os.path.join(BASE_DIR, 'static'),
-]
-
-# collectstatic directory
-STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
+"""
+Django settings for WebApp project.
+
+Generated by 'django-admin startproject' using Django 2.2.3.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/2.2/ref/settings/
+"""
+
+import os
+import json
+from django.core.cache import cache
+import ast
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+CONFIG_FILE = 'WebApp/config.ini'
+config = {}
+with open(CONFIG_FILE) as cfile:
+ config = json.load(cfile)
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = config["SECRET KEY"]
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = ['127.0.0.1']
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'about',
+ 'floor',
+ 'stats',
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+]
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'WebApp.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [os.path.join(BASE_DIR, 'templates'), BASE_DIR, os.path.join(BASE_DIR, 'templates/html')],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'WebApp.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+
+# cache settings
+# comment out for local running
+# CACHES = {
+# 'default':{
+# 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
+# 'LOCATION': '127.0.0.1:11211',
+# }
+# }
+
+LOGIN_REDIRECT_URL = '../about'
+
+LOGIN_URL = 'login'
+
+# LOGOUT_REDIRECT_ULR = 'about'
+
+for floor in config["FLOORS"]:
+ rooms = config["FLOORS"][floor]
+ rooms = ast.literal_eval(rooms)
+ cache.set('floor'+floor, rooms, None)
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.2/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'America/New_York'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = False
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.2/howto/static-files/
+
+STATIC_URL = '/static/'
+# Add directories for new pages here
+STATICFILES_DIRS = [
+ os.path.join(BASE_DIR, 'static'),
+ os.path.join(BASE_DIR, 'floor/static'),
+ os.path.join(BASE_DIR, 'about/static'),
+ os.path.join(BASE_DIR, 'stats/static')
+]
diff --git a/WebApp/WebApp/urls.py b/WebApp/WebApp/urls.py
new file mode 100644
index 00000000..0d3c5c28
--- /dev/null
+++ b/WebApp/WebApp/urls.py
@@ -0,0 +1,30 @@
+"""WebApp URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/2.2/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import include, path
+from django.contrib.auth import views as auth_views
+
+urlpatterns = [
+
+ path('', auth_views.LoginView.as_view(template_name='html/login.html'), name='login'),
+ path('about/', include('about.urls')),
+ path('floor/', include('floor.urls')),
+ path('about/', include('about.urls')),
+ path('stats/', include('stats.urls')),
+ path('admin/', admin.site.urls),
+ path('logout/', auth_views.LogoutView.as_view(template_name='html/logout.html'), name='logout'),
+ path('login/', auth_views.LoginView.as_view(template_name='html/login.html'), name='login'),
+]
diff --git a/_software/flom/wsgi.py b/WebApp/WebApp/wsgi.py
similarity index 56%
rename from _software/flom/wsgi.py
rename to WebApp/WebApp/wsgi.py
index f3061c65..579c99e7 100644
--- a/_software/flom/wsgi.py
+++ b/WebApp/WebApp/wsgi.py
@@ -1,16 +1,16 @@
-"""
-WSGI config for flom project.
-
-It exposes the WSGI callable as a module-level variable named ``application``.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
-"""
-
-import os
-
-from django.core.wsgi import get_wsgi_application
-
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'flom.settings')
-
-application = get_wsgi_application()
+"""
+WSGI config for WebApp project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'WebApp.settings')
+
+application = get_wsgi_application()
diff --git a/WebApp/about/__init__.py b/WebApp/about/__init__.py
new file mode 100644
index 00000000..a0b0cad5
--- /dev/null
+++ b/WebApp/about/__init__.py
@@ -0,0 +1,3 @@
+'''
+Empty module file
+'''
\ No newline at end of file
diff --git a/_software/database/admin.py b/WebApp/about/admin.py
similarity index 52%
rename from _software/database/admin.py
rename to WebApp/about/admin.py
index 8c38f3f3..f1244222 100644
--- a/_software/database/admin.py
+++ b/WebApp/about/admin.py
@@ -1,3 +1 @@
-from django.contrib import admin
-
-# Register your models here.
+from django.contrib import admin
diff --git a/WebApp/about/apps.py b/WebApp/about/apps.py
new file mode 100644
index 00000000..6922d7ca
--- /dev/null
+++ b/WebApp/about/apps.py
@@ -0,0 +1,10 @@
+from django.apps import AppConfig
+
+
+class AboutConfig(AppConfig):
+ '''
+ About page app
+ @member (s)
+ name - name of application
+ '''
+ name = 'about'
diff --git a/_software/database/migrations/__init__.py b/WebApp/about/migrations/__init__.py
similarity index 100%
rename from _software/database/migrations/__init__.py
rename to WebApp/about/migrations/__init__.py
diff --git a/WebApp/about/models.py b/WebApp/about/models.py
new file mode 100644
index 00000000..24df1f3a
--- /dev/null
+++ b/WebApp/about/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# No models needed for admin page
diff --git a/WebApp/about/static/images/library.png b/WebApp/about/static/images/library.png
new file mode 100644
index 00000000..65d6b50b
Binary files /dev/null and b/WebApp/about/static/images/library.png differ
diff --git a/WebApp/about/static/images/logo1.jpg b/WebApp/about/static/images/logo1.jpg
new file mode 100644
index 00000000..ebfc8f58
Binary files /dev/null and b/WebApp/about/static/images/logo1.jpg differ
diff --git a/WebApp/about/templates/html/about.html b/WebApp/about/templates/html/about.html
new file mode 100644
index 00000000..2943cd4d
--- /dev/null
+++ b/WebApp/about/templates/html/about.html
@@ -0,0 +1,55 @@
+{# about.html #}
+{# template for displaying the about page (prolly like a paragraph about our tech stack) #}
+{% extends "html/main.html" %}
+{% load static %}
+
+{% block styles %}
+
+{% endblock %}
+
+{% block body %}
+
+
+
+
+
+
Folsom Library Occupancy Monitor
+
FLOM (Folsom Library Occupancy Monitor) is an open source project
+ made by students in the Rensselaer Center for Open Source class
+ at RPI. Our mission is to provide students with a helpful application
+ that allows them to see which study rooms are available before going
+ to the library. If you have any issues or find any bugs, please raise
+ an issue at this
+ link .
+
+
How to Use the App?
+
See the navigation bar floating at the top of the webpage? Just
+ click the floor you want to study on and check the availability online!
+ For a more detailed tutorial, go throught the
+ WIKI page.
+
+
Join Us!
+
If you are interested in this project, please check the github page and contact our main developer.
+
+
+ Developers (Spring 2019):
+
+
prashb99 ,
+
Wixby ,
jgaltman ,
+
youngcc3157 ,
kaijianZ ,
+
jingsting
+
+ Developers (Summer 2019):
+
+
prashb99 ,
+
Jason-Durr ,
SquidThePrinter ,
+
Jiawen-Lin ,
Jcherella ,
+
barnesv17 ,
Emmanuel Sylvester ,
+
ChrisReed0114 ,
Junyi Zhang
+
+
+
+
+
+
+{% endblock %}
diff --git a/WebApp/about/tests.py b/WebApp/about/tests.py
new file mode 100644
index 00000000..6ff7ca78
--- /dev/null
+++ b/WebApp/about/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# TODO: create tests for admin page
diff --git a/WebApp/about/urls.py b/WebApp/about/urls.py
new file mode 100644
index 00000000..4815c1ba
--- /dev/null
+++ b/WebApp/about/urls.py
@@ -0,0 +1,10 @@
+from django.urls import path
+from . import views
+
+'''
+This will find the corresponding view
+named "index"
+'''
+urlpatterns = [
+ path('',views.index, name="index"),
+]
diff --git a/WebApp/about/views.py b/WebApp/about/views.py
new file mode 100644
index 00000000..740daab4
--- /dev/null
+++ b/WebApp/about/views.py
@@ -0,0 +1,11 @@
+from django.shortcuts import render, render_to_response
+
+from django.contrib.auth.decorators import login_required
+
+
+# Create your views here. A view is a Python function that takes a web request and returns a web response.
+def index(request):
+ '''
+ @return the display for the about page
+ '''
+ return render_to_response('about/templates/html/about.html')
diff --git a/WebApp/db.sqlite3 b/WebApp/db.sqlite3
new file mode 100644
index 00000000..a1577fa2
Binary files /dev/null and b/WebApp/db.sqlite3 differ
diff --git a/_software/flom/__init__.py b/WebApp/floor/__init__.py
similarity index 100%
rename from _software/flom/__init__.py
rename to WebApp/floor/__init__.py
diff --git a/WebApp/floor/admin.py b/WebApp/floor/admin.py
new file mode 100644
index 00000000..d6f0fde3
--- /dev/null
+++ b/WebApp/floor/admin.py
@@ -0,0 +1,18 @@
+from django.contrib import admin
+
+from .models import Floor, Room
+
+class FloorAdmin(admin.ModelAdmin):
+ '''
+ Model for displaying info on admin page for Floor model
+ '''
+ list_display = ('name', 'roomCount')
+
+class RoomAdmin(admin.ModelAdmin):
+ '''
+ Model for displaying info on admin page for Room model
+ '''
+ list_display = ('roomID', 'occupied', 'lastExited', 'lastEntered', 'roomType', 'floor')
+
+admin.site.register(Floor, FloorAdmin)
+admin.site.register(Room, RoomAdmin)
\ No newline at end of file
diff --git a/WebApp/floor/apps.py b/WebApp/floor/apps.py
new file mode 100644
index 00000000..7d0f7740
--- /dev/null
+++ b/WebApp/floor/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class FloorConfig(AppConfig):
+ name = 'floor'
diff --git a/WebApp/floor/migrations/0001_initial.py b/WebApp/floor/migrations/0001_initial.py
new file mode 100644
index 00000000..40bf9b40
--- /dev/null
+++ b/WebApp/floor/migrations/0001_initial.py
@@ -0,0 +1,35 @@
+# Generated by Django 2.2.4 on 2019-10-07 22:38
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Floor',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=6)),
+ ('roomCount', models.IntegerField(default=0)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Room',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('roomID', models.CharField(max_length=5)),
+ ('occupied', models.IntegerField()),
+ ('lastExited', models.DateField()),
+ ('lastEntered', models.DateField()),
+ ('roomType', models.CharField(default='S', max_length=6)),
+ ('floor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='floor.Floor')),
+ ],
+ ),
+ ]
diff --git a/_software/library_monitor/__init__.py b/WebApp/floor/migrations/__init__.py
similarity index 100%
rename from _software/library_monitor/__init__.py
rename to WebApp/floor/migrations/__init__.py
diff --git a/WebApp/floor/models.py b/WebApp/floor/models.py
new file mode 100644
index 00000000..a5024a19
--- /dev/null
+++ b/WebApp/floor/models.py
@@ -0,0 +1,28 @@
+from django.db import models
+
+class Floor(models.Model):
+ '''
+ This floor model is used to represent both floor 3 and floor 4
+ @member (s)
+ floor - 'floor3' or 'floor4'
+ '''
+ name = models.CharField(max_length=6)
+ roomCount = models.IntegerField(default=0)
+
+class Room(models.Model):
+ '''
+ Model for a Room
+ @member (s)
+ roomID - the number of the room (ex. 301, 324)
+ occupied - occupation status of the room (0 = false, 1 = true)
+ lastExited - date of last exit
+ lastEntered - date of last entry
+ roomType - group or single room
+ floor - points to the floor that the room belongs to
+ '''
+ roomID = models.CharField(max_length = 5) # ID of room (Ex. 301, 324)
+ occupied = models.IntegerField() # 0 for empty, 1 for occupied
+ lastExited = models.DateField()
+ lastEntered = models.DateField()
+ roomType = models.CharField(max_length=6, default='S') #single/group for now, could get more descriptive potentially
+ floor = models.ForeignKey(Floor, on_delete=models.CASCADE) # room gets mapped to a floor
diff --git a/_software/library_monitor/static/library_monitor/images/311.png b/WebApp/floor/static/images/floor3/311.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/311.png
rename to WebApp/floor/static/images/floor3/311.png
diff --git a/_software/library_monitor/static/library_monitor/images/311_red.png b/WebApp/floor/static/images/floor3/311_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/311_red.png
rename to WebApp/floor/static/images/floor3/311_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/323A.png b/WebApp/floor/static/images/floor3/323A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/323A.png
rename to WebApp/floor/static/images/floor3/323A.png
diff --git a/_software/library_monitor/static/library_monitor/images/323A_red.png b/WebApp/floor/static/images/floor3/323A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/323A_red.png
rename to WebApp/floor/static/images/floor3/323A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/323B.png b/WebApp/floor/static/images/floor3/323B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/323B.png
rename to WebApp/floor/static/images/floor3/323B.png
diff --git a/_software/library_monitor/static/library_monitor/images/323B_red.png b/WebApp/floor/static/images/floor3/323B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/323B_red.png
rename to WebApp/floor/static/images/floor3/323B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/323C.png b/WebApp/floor/static/images/floor3/323C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/323C.png
rename to WebApp/floor/static/images/floor3/323C.png
diff --git a/_software/library_monitor/static/library_monitor/images/323C_red.png b/WebApp/floor/static/images/floor3/323C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/323C_red.png
rename to WebApp/floor/static/images/floor3/323C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/332A.png b/WebApp/floor/static/images/floor3/332A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332A.png
rename to WebApp/floor/static/images/floor3/332A.png
diff --git a/_software/library_monitor/static/library_monitor/images/332A_red.png b/WebApp/floor/static/images/floor3/332A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332A_red.png
rename to WebApp/floor/static/images/floor3/332A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/332B.png b/WebApp/floor/static/images/floor3/332B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332B.png
rename to WebApp/floor/static/images/floor3/332B.png
diff --git a/_software/library_monitor/static/library_monitor/images/332B_red.png b/WebApp/floor/static/images/floor3/332B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332B_red.png
rename to WebApp/floor/static/images/floor3/332B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/332C.png b/WebApp/floor/static/images/floor3/332C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332C.png
rename to WebApp/floor/static/images/floor3/332C.png
diff --git a/_software/library_monitor/static/library_monitor/images/332C_red.png b/WebApp/floor/static/images/floor3/332C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332C_red.png
rename to WebApp/floor/static/images/floor3/332C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/332D.png b/WebApp/floor/static/images/floor3/332D.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332D.png
rename to WebApp/floor/static/images/floor3/332D.png
diff --git a/_software/library_monitor/static/library_monitor/images/332D_red.png b/WebApp/floor/static/images/floor3/332D_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332D_red.png
rename to WebApp/floor/static/images/floor3/332D_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/332E.png b/WebApp/floor/static/images/floor3/332E.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332E.png
rename to WebApp/floor/static/images/floor3/332E.png
diff --git a/_software/library_monitor/static/library_monitor/images/332E_red.png b/WebApp/floor/static/images/floor3/332E_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/332E_red.png
rename to WebApp/floor/static/images/floor3/332E_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/333.png b/WebApp/floor/static/images/floor3/333.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/333.png
rename to WebApp/floor/static/images/floor3/333.png
diff --git a/_software/library_monitor/static/library_monitor/images/333_red.png b/WebApp/floor/static/images/floor3/333_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/333_red.png
rename to WebApp/floor/static/images/floor3/333_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/337A.png b/WebApp/floor/static/images/floor3/337A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337A.png
rename to WebApp/floor/static/images/floor3/337A.png
diff --git a/_software/library_monitor/static/library_monitor/images/337A_red.png b/WebApp/floor/static/images/floor3/337A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337A_red.png
rename to WebApp/floor/static/images/floor3/337A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/337B.png b/WebApp/floor/static/images/floor3/337B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337B.png
rename to WebApp/floor/static/images/floor3/337B.png
diff --git a/_software/library_monitor/static/library_monitor/images/337B_red.png b/WebApp/floor/static/images/floor3/337B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337B_red.png
rename to WebApp/floor/static/images/floor3/337B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/337C.png b/WebApp/floor/static/images/floor3/337C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337C.png
rename to WebApp/floor/static/images/floor3/337C.png
diff --git a/_software/library_monitor/static/library_monitor/images/337C_red.png b/WebApp/floor/static/images/floor3/337C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337C_red.png
rename to WebApp/floor/static/images/floor3/337C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/337D.png b/WebApp/floor/static/images/floor3/337D.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337D.png
rename to WebApp/floor/static/images/floor3/337D.png
diff --git a/_software/library_monitor/static/library_monitor/images/337D_red.png b/WebApp/floor/static/images/floor3/337D_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337D_red.png
rename to WebApp/floor/static/images/floor3/337D_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/337E.png b/WebApp/floor/static/images/floor3/337E.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337E.png
rename to WebApp/floor/static/images/floor3/337E.png
diff --git a/_software/library_monitor/static/library_monitor/images/337E_red.png b/WebApp/floor/static/images/floor3/337E_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/337E_red.png
rename to WebApp/floor/static/images/floor3/337E_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/342A.png b/WebApp/floor/static/images/floor3/342A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/342A.png
rename to WebApp/floor/static/images/floor3/342A.png
diff --git a/_software/library_monitor/static/library_monitor/images/342A_red.png b/WebApp/floor/static/images/floor3/342A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/342A_red.png
rename to WebApp/floor/static/images/floor3/342A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/342B.png b/WebApp/floor/static/images/floor3/342B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/342B.png
rename to WebApp/floor/static/images/floor3/342B.png
diff --git a/_software/library_monitor/static/library_monitor/images/342B_red.png b/WebApp/floor/static/images/floor3/342B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/342B_red.png
rename to WebApp/floor/static/images/floor3/342B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/342C.png b/WebApp/floor/static/images/floor3/342C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/342C.png
rename to WebApp/floor/static/images/floor3/342C.png
diff --git a/_software/library_monitor/static/library_monitor/images/342C_red.png b/WebApp/floor/static/images/floor3/342C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/342C_red.png
rename to WebApp/floor/static/images/floor3/342C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/352A.png b/WebApp/floor/static/images/floor3/352A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352A.png
rename to WebApp/floor/static/images/floor3/352A.png
diff --git a/_software/library_monitor/static/library_monitor/images/352A_red.png b/WebApp/floor/static/images/floor3/352A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352A_red.png
rename to WebApp/floor/static/images/floor3/352A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/352B.png b/WebApp/floor/static/images/floor3/352B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352B.png
rename to WebApp/floor/static/images/floor3/352B.png
diff --git a/_software/library_monitor/static/library_monitor/images/352B_red.png b/WebApp/floor/static/images/floor3/352B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352B_red.png
rename to WebApp/floor/static/images/floor3/352B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/352C.png b/WebApp/floor/static/images/floor3/352C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352C.png
rename to WebApp/floor/static/images/floor3/352C.png
diff --git a/_software/library_monitor/static/library_monitor/images/352C_red.png b/WebApp/floor/static/images/floor3/352C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352C_red.png
rename to WebApp/floor/static/images/floor3/352C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/352D.png b/WebApp/floor/static/images/floor3/352D.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352D.png
rename to WebApp/floor/static/images/floor3/352D.png
diff --git a/_software/library_monitor/static/library_monitor/images/352D_red.png b/WebApp/floor/static/images/floor3/352D_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352D_red.png
rename to WebApp/floor/static/images/floor3/352D_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/352E.png b/WebApp/floor/static/images/floor3/352E.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352E.png
rename to WebApp/floor/static/images/floor3/352E.png
diff --git a/_software/library_monitor/static/library_monitor/images/352E_red.png b/WebApp/floor/static/images/floor3/352E_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/352E_red.png
rename to WebApp/floor/static/images/floor3/352E_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/353A.png b/WebApp/floor/static/images/floor3/353A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/353A.png
rename to WebApp/floor/static/images/floor3/353A.png
diff --git a/_software/library_monitor/static/library_monitor/images/353A_red.png b/WebApp/floor/static/images/floor3/353A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/353A_red.png
rename to WebApp/floor/static/images/floor3/353A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/353B.png b/WebApp/floor/static/images/floor3/353B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/353B.png
rename to WebApp/floor/static/images/floor3/353B.png
diff --git a/_software/library_monitor/static/library_monitor/images/353B_red.png b/WebApp/floor/static/images/floor3/353B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/353B_red.png
rename to WebApp/floor/static/images/floor3/353B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/f3_nobg_s.png b/WebApp/floor/static/images/floor3/floor3template.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/f3_nobg_s.png
rename to WebApp/floor/static/images/floor3/floor3template.png
diff --git a/_software/library_monitor/static/library_monitor/images/423A.png b/WebApp/floor/static/images/floor4/423A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423A.png
rename to WebApp/floor/static/images/floor4/423A.png
diff --git a/_software/library_monitor/static/library_monitor/images/423A_red.png b/WebApp/floor/static/images/floor4/423A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423A_red.png
rename to WebApp/floor/static/images/floor4/423A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/423B.png b/WebApp/floor/static/images/floor4/423B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423B.png
rename to WebApp/floor/static/images/floor4/423B.png
diff --git a/_software/library_monitor/static/library_monitor/images/423B_red.png b/WebApp/floor/static/images/floor4/423B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423B_red.png
rename to WebApp/floor/static/images/floor4/423B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/423C.png b/WebApp/floor/static/images/floor4/423C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423C.png
rename to WebApp/floor/static/images/floor4/423C.png
diff --git a/_software/library_monitor/static/library_monitor/images/423C_red.png b/WebApp/floor/static/images/floor4/423C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423C_red.png
rename to WebApp/floor/static/images/floor4/423C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/423D.png b/WebApp/floor/static/images/floor4/423D.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423D.png
rename to WebApp/floor/static/images/floor4/423D.png
diff --git a/_software/library_monitor/static/library_monitor/images/423D_red.png b/WebApp/floor/static/images/floor4/423D_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423D_red.png
rename to WebApp/floor/static/images/floor4/423D_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/423E.png b/WebApp/floor/static/images/floor4/423E.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423E.png
rename to WebApp/floor/static/images/floor4/423E.png
diff --git a/_software/library_monitor/static/library_monitor/images/423E_red.png b/WebApp/floor/static/images/floor4/423E_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/423E_red.png
rename to WebApp/floor/static/images/floor4/423E_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/424A.png b/WebApp/floor/static/images/floor4/424A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/424A.png
rename to WebApp/floor/static/images/floor4/424A.png
diff --git a/_software/library_monitor/static/library_monitor/images/424A_red.png b/WebApp/floor/static/images/floor4/424A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/424A_red.png
rename to WebApp/floor/static/images/floor4/424A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/424B.png b/WebApp/floor/static/images/floor4/424B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/424B.png
rename to WebApp/floor/static/images/floor4/424B.png
diff --git a/_software/library_monitor/static/library_monitor/images/424B_red.png b/WebApp/floor/static/images/floor4/424B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/424B_red.png
rename to WebApp/floor/static/images/floor4/424B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/431.png b/WebApp/floor/static/images/floor4/431.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/431.png
rename to WebApp/floor/static/images/floor4/431.png
diff --git a/_software/library_monitor/static/library_monitor/images/431_red.png b/WebApp/floor/static/images/floor4/431_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/431_red.png
rename to WebApp/floor/static/images/floor4/431_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/432.png b/WebApp/floor/static/images/floor4/432.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/432.png
rename to WebApp/floor/static/images/floor4/432.png
diff --git a/_software/library_monitor/static/library_monitor/images/432_red.png b/WebApp/floor/static/images/floor4/432_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/432_red.png
rename to WebApp/floor/static/images/floor4/432_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/433A.png b/WebApp/floor/static/images/floor4/433A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/433A.png
rename to WebApp/floor/static/images/floor4/433A.png
diff --git a/_software/library_monitor/static/library_monitor/images/433A_red.png b/WebApp/floor/static/images/floor4/433A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/433A_red.png
rename to WebApp/floor/static/images/floor4/433A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/435D.png b/WebApp/floor/static/images/floor4/435D.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/435D.png
rename to WebApp/floor/static/images/floor4/435D.png
diff --git a/_software/library_monitor/static/library_monitor/images/435D_red.png b/WebApp/floor/static/images/floor4/435D_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/435D_red.png
rename to WebApp/floor/static/images/floor4/435D_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/437A.png b/WebApp/floor/static/images/floor4/437A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/437A.png
rename to WebApp/floor/static/images/floor4/437A.png
diff --git a/_software/library_monitor/static/library_monitor/images/437A_red.png b/WebApp/floor/static/images/floor4/437A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/437A_red.png
rename to WebApp/floor/static/images/floor4/437A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/437B.png b/WebApp/floor/static/images/floor4/437B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/437B.png
rename to WebApp/floor/static/images/floor4/437B.png
diff --git a/_software/library_monitor/static/library_monitor/images/437B_red.png b/WebApp/floor/static/images/floor4/437B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/437B_red.png
rename to WebApp/floor/static/images/floor4/437B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/437C.png b/WebApp/floor/static/images/floor4/437C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/437C.png
rename to WebApp/floor/static/images/floor4/437C.png
diff --git a/_software/library_monitor/static/library_monitor/images/437C_red.png b/WebApp/floor/static/images/floor4/437C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/437C_red.png
rename to WebApp/floor/static/images/floor4/437C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/438.png b/WebApp/floor/static/images/floor4/438.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/438.png
rename to WebApp/floor/static/images/floor4/438.png
diff --git a/_software/library_monitor/static/library_monitor/images/438_red.png b/WebApp/floor/static/images/floor4/438_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/438_red.png
rename to WebApp/floor/static/images/floor4/438_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/441A.png b/WebApp/floor/static/images/floor4/441A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/441A.png
rename to WebApp/floor/static/images/floor4/441A.png
diff --git a/_software/library_monitor/static/library_monitor/images/441A_red.png b/WebApp/floor/static/images/floor4/441A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/441A_red.png
rename to WebApp/floor/static/images/floor4/441A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/441B.png b/WebApp/floor/static/images/floor4/441B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/441B.png
rename to WebApp/floor/static/images/floor4/441B.png
diff --git a/_software/library_monitor/static/library_monitor/images/441B_red.png b/WebApp/floor/static/images/floor4/441B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/441B_red.png
rename to WebApp/floor/static/images/floor4/441B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/442A.png b/WebApp/floor/static/images/floor4/442A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442A.png
rename to WebApp/floor/static/images/floor4/442A.png
diff --git a/_software/library_monitor/static/library_monitor/images/442A_red.png b/WebApp/floor/static/images/floor4/442A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442A_red.png
rename to WebApp/floor/static/images/floor4/442A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/442B.png b/WebApp/floor/static/images/floor4/442B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442B.png
rename to WebApp/floor/static/images/floor4/442B.png
diff --git a/_software/library_monitor/static/library_monitor/images/442B_red.png b/WebApp/floor/static/images/floor4/442B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442B_red.png
rename to WebApp/floor/static/images/floor4/442B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/442C.png b/WebApp/floor/static/images/floor4/442C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442C.png
rename to WebApp/floor/static/images/floor4/442C.png
diff --git a/_software/library_monitor/static/library_monitor/images/442C_red.png b/WebApp/floor/static/images/floor4/442C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442C_red.png
rename to WebApp/floor/static/images/floor4/442C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/442D.png b/WebApp/floor/static/images/floor4/442D.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442D.png
rename to WebApp/floor/static/images/floor4/442D.png
diff --git a/_software/library_monitor/static/library_monitor/images/442D_red.png b/WebApp/floor/static/images/floor4/442D_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442D_red.png
rename to WebApp/floor/static/images/floor4/442D_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/442E.png b/WebApp/floor/static/images/floor4/442E.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442E.png
rename to WebApp/floor/static/images/floor4/442E.png
diff --git a/_software/library_monitor/static/library_monitor/images/442E_red.png b/WebApp/floor/static/images/floor4/442E_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/442E_red.png
rename to WebApp/floor/static/images/floor4/442E_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/451.png b/WebApp/floor/static/images/floor4/451.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/451.png
rename to WebApp/floor/static/images/floor4/451.png
diff --git a/_software/library_monitor/static/library_monitor/images/451_red.png b/WebApp/floor/static/images/floor4/451_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/451_red.png
rename to WebApp/floor/static/images/floor4/451_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/453A.png b/WebApp/floor/static/images/floor4/453A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453A.png
rename to WebApp/floor/static/images/floor4/453A.png
diff --git a/_software/library_monitor/static/library_monitor/images/453A_red.png b/WebApp/floor/static/images/floor4/453A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453A_red.png
rename to WebApp/floor/static/images/floor4/453A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/453B.png b/WebApp/floor/static/images/floor4/453B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453B.png
rename to WebApp/floor/static/images/floor4/453B.png
diff --git a/_software/library_monitor/static/library_monitor/images/453B_red.png b/WebApp/floor/static/images/floor4/453B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453B_red.png
rename to WebApp/floor/static/images/floor4/453B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/453C.png b/WebApp/floor/static/images/floor4/453C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453C.png
rename to WebApp/floor/static/images/floor4/453C.png
diff --git a/_software/library_monitor/static/library_monitor/images/453C_red.png b/WebApp/floor/static/images/floor4/453C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453C_red.png
rename to WebApp/floor/static/images/floor4/453C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/453D.png b/WebApp/floor/static/images/floor4/453D.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453D.png
rename to WebApp/floor/static/images/floor4/453D.png
diff --git a/_software/library_monitor/static/library_monitor/images/453D_red.png b/WebApp/floor/static/images/floor4/453D_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453D_red.png
rename to WebApp/floor/static/images/floor4/453D_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/453E.png b/WebApp/floor/static/images/floor4/453E.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453E.png
rename to WebApp/floor/static/images/floor4/453E.png
diff --git a/_software/library_monitor/static/library_monitor/images/453E_red.png b/WebApp/floor/static/images/floor4/453E_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/453E_red.png
rename to WebApp/floor/static/images/floor4/453E_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/454.png b/WebApp/floor/static/images/floor4/454.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/454.png
rename to WebApp/floor/static/images/floor4/454.png
diff --git a/_software/library_monitor/static/library_monitor/images/454_red.png b/WebApp/floor/static/images/floor4/454_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/454_red.png
rename to WebApp/floor/static/images/floor4/454_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/455.png b/WebApp/floor/static/images/floor4/455.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/455.png
rename to WebApp/floor/static/images/floor4/455.png
diff --git a/_software/library_monitor/static/library_monitor/images/455_red.png b/WebApp/floor/static/images/floor4/455_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/455_red.png
rename to WebApp/floor/static/images/floor4/455_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/456.png b/WebApp/floor/static/images/floor4/456.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/456.png
rename to WebApp/floor/static/images/floor4/456.png
diff --git a/_software/library_monitor/static/library_monitor/images/456_red.png b/WebApp/floor/static/images/floor4/456_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/456_red.png
rename to WebApp/floor/static/images/floor4/456_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/457A.png b/WebApp/floor/static/images/floor4/457A.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457A.png
rename to WebApp/floor/static/images/floor4/457A.png
diff --git a/_software/library_monitor/static/library_monitor/images/457A_red.png b/WebApp/floor/static/images/floor4/457A_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457A_red.png
rename to WebApp/floor/static/images/floor4/457A_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/457B.png b/WebApp/floor/static/images/floor4/457B.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457B.png
rename to WebApp/floor/static/images/floor4/457B.png
diff --git a/_software/library_monitor/static/library_monitor/images/457B_red.png b/WebApp/floor/static/images/floor4/457B_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457B_red.png
rename to WebApp/floor/static/images/floor4/457B_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/457C.png b/WebApp/floor/static/images/floor4/457C.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457C.png
rename to WebApp/floor/static/images/floor4/457C.png
diff --git a/_software/library_monitor/static/library_monitor/images/457C_red.png b/WebApp/floor/static/images/floor4/457C_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457C_red.png
rename to WebApp/floor/static/images/floor4/457C_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/457D.png b/WebApp/floor/static/images/floor4/457D.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457D.png
rename to WebApp/floor/static/images/floor4/457D.png
diff --git a/_software/library_monitor/static/library_monitor/images/457D_red.png b/WebApp/floor/static/images/floor4/457D_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457D_red.png
rename to WebApp/floor/static/images/floor4/457D_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/457E.png b/WebApp/floor/static/images/floor4/457E.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457E.png
rename to WebApp/floor/static/images/floor4/457E.png
diff --git a/_software/library_monitor/static/library_monitor/images/457E_red.png b/WebApp/floor/static/images/floor4/457E_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/457E_red.png
rename to WebApp/floor/static/images/floor4/457E_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/458.png b/WebApp/floor/static/images/floor4/458.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/458.png
rename to WebApp/floor/static/images/floor4/458.png
diff --git a/_software/library_monitor/static/library_monitor/images/458_red.png b/WebApp/floor/static/images/floor4/458_red.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/458_red.png
rename to WebApp/floor/static/images/floor4/458_red.png
diff --git a/_software/library_monitor/static/library_monitor/images/f4_nobg_s.png b/WebApp/floor/static/images/floor4/floor4template.png
similarity index 100%
rename from _software/library_monitor/static/library_monitor/images/f4_nobg_s.png
rename to WebApp/floor/static/images/floor4/floor4template.png
diff --git a/WebApp/floor/templates/html/floor3.html b/WebApp/floor/templates/html/floor3.html
new file mode 100644
index 00000000..5238ba65
--- /dev/null
+++ b/WebApp/floor/templates/html/floor3.html
@@ -0,0 +1,32 @@
+{# floor3.html #}
+{# template for displaying the 3rd floor of the library #}
+{% extends "html/main.html" %}
+{% load static %}
+
+{% block styles %}
+
+
+
+{% endblock %}
+
+{% block body %}
+{# Image of Library Floor 3#}
+
+{# Loop to show which rooms are Occupied and Unoccupied #}
+{% for room in Rooms %}
+ {% if room.occupied %}
+ {# Occupied Rooms #}
+ {% with 'images/floor3/'|add:room.ID|add:"_red.png" as occupied %}
+
+ {% endwith %}
+ {% else %}
+ {# Unoccupied Rooms #}
+ {% with 'images/floor3/'|add:room.ID|add:".png" as occupied %}
+
+ {% endwith %}
+ {% endif %}
+
+
+{% endfor %}
+
+{% endblock %}
diff --git a/WebApp/floor/templates/html/floor4.html b/WebApp/floor/templates/html/floor4.html
new file mode 100644
index 00000000..97621a7e
--- /dev/null
+++ b/WebApp/floor/templates/html/floor4.html
@@ -0,0 +1,32 @@
+{# floor4.html #}
+{# template for displaying the 3rd floor of the library #}
+{% extends "html/main.html" %}
+{% load static %}
+
+{% block styles %}
+
+
+
+{% endblock %}
+
+{% block body %}
+{# Image of Library Floor 4#}
+
+{# Loop to show which rooms are Occupied and Unoccupied #}
+{% for room in Rooms %}
+ {% if room.occupied %}
+ {# Occupied Rooms #}
+ {% with 'images/floor4/'|add:room.ID|add:"_red.png" as occupied %}
+
+ {% endwith %}
+ {% else %}
+ {# Unoccupied roooms #}
+ {% with 'images/floor4/'|add:room.ID|add:".png" as occupied %}
+
+ {% endwith %}
+ {% endif %}
+
+
+{% endfor %}
+
+{% endblock %}
diff --git a/WebApp/floor/tests.py b/WebApp/floor/tests.py
new file mode 100644
index 00000000..14ffa900
--- /dev/null
+++ b/WebApp/floor/tests.py
@@ -0,0 +1,87 @@
+import ast
+import json
+
+from django.test import TestCase
+from . import views
+from django.test import Client
+from django.http import HttpResponse
+
+# Create your tests here.
+class BasicTestCase(TestCase):
+ print("Testing simply entering and exiting a room that exists (311)")
+ #Enter Room Success
+ #Must Login to enter the room
+ c = Client()
+ c.login(username='admin', password='admin')
+ #Enter Room
+ response = c.get("http://127.0.0.1:8000/floor/enter/3/311/pass") #Response is of type byte
+ response_string = (response.content).decode('ASCII') #To String
+ assert(response_string == "Room successfully entered!")
+ print("Room successfully entered!")
+ #Exit Room
+ response = c.get("http://127.0.0.1:8000/floor/exit/3/311/pass") #Response is of type byte
+ response_string = (response.content).decode('ASCII') #To String
+ assert(response_string == "Room successfully exited!")
+ print("Room successfully exited!")
+
+# Create your tests here.
+class WrongRoom(TestCase):
+ print("Testing entering and exiting a room that does not exist (300)")
+ #Enter Room Success
+ #Must Login to enter the room
+ c = Client()
+ c.login(username='admin', password='admin')
+ #Enter Room
+ response = c.get("http://127.0.0.1:8000/floor/enter/3/300/pass") #Response is of type byte
+ response_string = (response.content).decode('ASCII') #To String
+ assert(response_string == "Room Not Found")
+ print("Room Not Found")
+ #Exit Room
+ response = c.get("http://127.0.0.1:8000/floor/exit/3/300/pass") #Response is of type byte
+ response_string = (response.content).decode('ASCII') #To String
+ assert(response_string == "Room Not Found")
+ print("Room Not Found")
+
+# Create your tests here.
+class DoneAlready(TestCase):
+ print("Trying to enter and exit multiple times back to back")
+ #Enter Room Success
+ #Must Login to enter the room
+ c = Client()
+ c.login(username='admin', password='admin')
+ #Enter Room
+ response = c.get("http://127.0.0.1:8000/floor/enter/3/311/pass") #Response is of type byte
+ response = c.get("http://127.0.0.1:8000/floor/enter/3/311/pass") #Response is of type byte
+ response_string = (response.content).decode('ASCII') #To String
+ assert(response_string == "Room already occupied")
+ print("Room already occupied")
+ #Exit Room
+ response = c.get("http://127.0.0.1:8000/floor/exit/3/311/pass") #Response is of type byte
+ response = c.get("http://127.0.0.1:8000/floor/exit/3/311/pass") #Response is of type byte
+ response_string = (response.content).decode('ASCII') #To String
+ assert(response_string == "Room already empty")
+ print("Room already empty")
+
+
+class AllRooms(TestCase):
+ print("Going to enter and exit every room")
+ #Load all of the rooms
+ CONFIG_FILE = 'WebApp/config.ini'
+ config = {}
+ with open(CONFIG_FILE) as cfile:
+ config = json.load(cfile)
+ #Login to exit and enter
+ c = Client()
+ c.login(username='admin', password='admin')
+ #Loop through all of the floors
+ for floor in config["FLOORS"]:
+ rooms = config["FLOORS"][floor]
+ rooms = ast.literal_eval(rooms)
+ print("On floor:", floor)
+ #Loop through all of the rooms
+ for room in rooms:
+ #Enter the room
+ response = c.get("http://127.0.0.1:8000/floor/enter/{}/{}/pass".format(floor,room))
+ #Exit the room
+ response = c.get("http://127.0.0.1:8000/floor/exit/{}/{}/pass".format(floor,room))
+ print("All Rooms successfully exited and entered!!!")
diff --git a/WebApp/floor/urls.py b/WebApp/floor/urls.py
new file mode 100644
index 00000000..50037e9a
--- /dev/null
+++ b/WebApp/floor/urls.py
@@ -0,0 +1,24 @@
+from django.urls import path
+from . import views
+
+'''
+index - This will find the corresponding view named "index"
+ - floor argument passed in to function ('3' or '4')
+enterRoom - This will find the corresponding view named "enterRoom"
+ - floor ('3' or '4')
+ - ID (room ID)
+ - Password (password for RasberryPi device)
+exitRoom - This will find the correspoding view named "exitRoom"
+ - floor ('3' or '4')
+ - ID (room ID)
+ - Password (password for RasberryPi device)
+'''
+urlpatterns = [
+ path("", views.index, name="index"),
+ path("enter///", views.enterRoom, name = "enterRoom"),
+ path("exit///", views.exitRoom, name= "exitRoom")
+]
+
+# initalize database with data from config.ini file
+# ONLY CALLED ONCE AT SERVER STARTUP
+views.populateFloors()
\ No newline at end of file
diff --git a/WebApp/floor/views.py b/WebApp/floor/views.py
new file mode 100644
index 00000000..d17803b6
--- /dev/null
+++ b/WebApp/floor/views.py
@@ -0,0 +1,147 @@
+from django.shortcuts import render_to_response
+from django.http import HttpResponse
+from django.core.cache import cache
+from django.template import RequestContext
+from datetime import datetime
+from stats.views import log
+from .models import Floor, Room
+# Create your views here. A view is a Python function that takes a web request and returns a web response.
+from django.contrib.auth.decorators import login_required
+
+
+
+#TODO: learn what actually gets put in on a page request
+
+floors = {} # floor['3'] = Floor('floor3') and same for 4
+rooms = {} # holds the rooms for all the floors
+
+def getUpdatedRoomsList(floor):
+ '''
+ Creates an updated version of the rooms list used for updating the webpage
+ @return a dictionary with (key = "Rooms", value = list of rooms and their occupancy)
+ '''
+ # create an empty dictionary and add key "Rooms" with empty list as value
+ roomList = {}
+ roomList["Rooms"] = []
+ # iterate through all the rooms on the floor
+ # get room data to add
+ # append room data to roomList
+ for room in floor.room_set.all():
+ add = {"ID": room.roomID, "occupied" : room.occupied}
+ roomList["Rooms"].append(add)
+ return roomList
+
+@login_required
+def index(request, floor):
+ '''
+ @return the display for floor
+ '''
+ return cache.get("display" + floor)
+
+@login_required
+def enterRoom(request, floor, ID, password):
+ '''
+ This function is called when someone enters a room
+ @modifies Room object with matching ID
+ @return Response to server
+ '''
+ # Check for room existence
+ if ID in rooms.keys():
+ currRoom = rooms[ID]
+ # if the current room is already occupied
+ if currRoom.occupied:
+ return HttpResponse("Room already occupied")
+ else:
+ # modify current room to occupied = True and update current datetime
+ currRoom.occupied = True
+ currRoom.lastEntered = datetime.now()
+ log(ID,1)
+ # save changes made to current room (to database)
+ currRoom.save()
+ # create the dictionary of rooms needed to update webpage
+ roomList = getUpdatedRoomsList(floors[floor])
+ # set the cache with the new room display based on changes made
+ display = render_to_response('floor/templates/html/floor' + floor + '.html', roomList)
+ cache.set("display" + floor, display, None)
+ return HttpResponse("Room successfully entered!")
+ # Room not found
+ else:
+ return HttpResponse("Room Not Found")
+
+@login_required
+def exitRoom(request, floor, ID, password):
+ '''
+ This function is called when someone exits a room
+ @modifies Room object with matching ID
+ @return Response to server
+ '''
+ # Check for room existence
+ if ID in rooms.keys():
+ currRoom = rooms[ID]
+ # if the room is empty
+ if not currRoom.occupied:
+ return HttpResponse("Room already empty")
+ else:
+ # modify current room to occupied = False and update current datetime
+ currRoom.occupied = False
+ currRoom.lastExited = datetime.now()
+ log(ID,0)
+ # save changes made to current room (to database)
+ currRoom.save()
+ # create dictionary of rooms needed to update webpage
+ roomList = getUpdatedRoomsList(floors[floor])
+ # set the cache with the new room display based on changes made
+ display = render_to_response('floor/templates/html/floor' + floor + '.html', roomList)
+ cache.set("display" + floor, display, None)
+ return HttpResponse("Room successfully exited!")
+ # Room not found
+ else:
+ return HttpResponse("Room Not Found")
+
+def createRooms(floor, IDs):
+ '''
+ Creates the rooms for an individual floor. If the Room with the ID exists, its pulled from
+ the database. Otherwise a new Room is created and assigned to the floor.
+ The roomsList gets generated for the floor and the display is set in the cache.
+ '''
+ for ID in IDs:
+ roomFound = Room.objects.filter(roomID=ID).count()
+ if roomFound > 0:
+ rooms[ID] = Room.objects.get(roomID=ID)
+ else:
+ # create new Room with corresponding floor
+ rooms[ID] = Room(roomID=ID, occupied=False, lastEntered=datetime.now(), lastExited=datetime.now(), floor=floor)
+ rooms[ID].save()
+ floor.roomCount += 1
+ floor.save()
+ roomList = getUpdatedRoomsList(floor)
+ display = render_to_response('floor/templates/html/' + floor.name + '.html', roomList)
+ cache.set('display'+floor.name[-1], display, None)
+
+def populateFloors():
+ '''
+ Fills the rooms dictionary with key = {ID}, value = {Room} (see Room object definition in models.py)
+ Should only be called once at startup
+ @modifies rooms
+ '''
+ # get the room IDs from the cache for the floor
+ floor3IDs = cache.get('floor3')
+ floor4IDs = cache.get('floor4')
+ floor3Found = Floor.objects.filter(name='floor3').count()
+ if floor3Found > 0:
+ floor3 = Floor.objects.get(name='floor3')
+ else:
+ floor3 = Floor(name='floor3')
+ floor3.save()
+ floor4Found = Floor.objects.filter(name='floor4').count()
+ if floor4Found > 0:
+ floor4 = Floor.objects.get(name='floor4')
+ else:
+ floor4 = Floor(name='floor4')
+ floor4.save()
+ floors['3'] = floor3
+ floors['4'] = floor4
+ print('Creating rooms for floor 3...')
+ createRooms(floor3, floor3IDs)
+ print('Creating rooms for floor 4...')
+ createRooms(floor4, floor4IDs)
\ No newline at end of file
diff --git a/WebApp/hardware/.vscode/settings.json b/WebApp/hardware/.vscode/settings.json
new file mode 100644
index 00000000..41e87a38
--- /dev/null
+++ b/WebApp/hardware/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "C_Cpp.errorSquiggles": "Disabled"
+}
\ No newline at end of file
diff --git a/WebApp/hardware/database/database.ino b/WebApp/hardware/database/database.ino
new file mode 100644
index 00000000..c39504a6
--- /dev/null
+++ b/WebApp/hardware/database/database.ino
@@ -0,0 +1,108 @@
+#include
+#include "radio_endpoint.h"
+#include "messages.h"
+#include "locations.h"
+
+hmap::Location database(DATABASE);
+RadioEndPoint radio_endpoint;
+const byte address[6] = "00001";
+
+void on_occupancy_msg(void *raw_msg)
+{
+ occupancy::Msg &o_msg = *static_cast(raw_msg);
+ Serial.write((byte *)(&o_msg.body), sizeof(occupancy::Body)); //writing a message
+}
+
+void setup()
+{
+ radio_endpoint.setup(address);
+ Serial.begin(9600);
+
+ database.subscribe(&on_occupancy_msg);
+ database.bind(radio_endpoint); //setting up radio channel for communication
+}
+
+const unsigned int cycle_delay = 250;
+
+void loop()
+{
+ //Serial.println(sizeof(occupancy::Body));
+ delay(cycle_delay);
+ database.cycle();
+}
+
+/*
+#include "hive_map.h"
+#include "hive_map.c"
+
+#define PIR 2 //connect PIR sensor to pin 2 of arduino
+#define LED 13 //connect LED for testing
+
+int PIR_STATE = LOW;
+int val = 0;
+byte timer = 0;
+bool cycle_flag = true;
+
+typedef struct Occupancy_Space { //creating an occupancy space
+ HiveMapSpaceId space;
+ bool isOccupied;
+} Occupancy_Space;
+
+HiveMapNode(Occupancy_Space) node; //room defined by occupancy space
+
+void setup_interrupts() {
+ noInterrupts(); // disable interrupts
+ // set up timer interput phase
+ TCCR1A = 0;
+ TCCR1B = 0;
+ TCNT1 = 0;
+ OCR1A = 31250; // compare match register (16MHz/256/2Hz)
+ TCCR1B |= (1 << WGM12); // CTC mode
+ TCCR1B |= (1 << CS12); // 256 prescaler
+ TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
+ interrupts(); // re-endable interrupts
+}
+
+ISR(TIMER1_COMPA_vect)
+{
+ TCNT1 = 34286; // timer duration
+ cycle_flag = true;
+ ++timer;
+}
+
+void setup(){
+ pinMode(LED, OUTPUT);
+ pinMode(PIR, INPUT);
+ setup_interrupts();
+ node.loc = 10; //room number
+ node.goal_loc = 1; //floor number
+ node.state_received = NULL;
+ Serial.begin(9600);
+}
+
+void loop(){
+ val = digitalRead(PIR);
+ if (val == HIGH) { // check if the input is HIGH
+ digitalWrite(LED, HIGH); // turn LED ON
+ if (PIR_STATE == LOW) {
+ Serial.println("Motion detected!");
+ PIR_STATE = HIGH;
+ node.state.isOccupied = true;
+ update_node(&node, sizeof(node)); //update node
+ }
+ }
+ else {
+ digitalWrite(LED, LOW); // turn LED OFF
+ if (PIR_STATE == HIGH){
+ Serial.println("Motion ended!");
+ PIR_STATE = LOW;
+ node.state.isOccupied = false;
+ update_node(&node, sizeof(node));
+ }
+ }
+ if(cycle_flag) {
+ cycle_node(&node, sizeof(node));
+ cycle_flag = false;
+ }
+}
+*/
diff --git a/WebApp/hardware/database/locations.h b/WebApp/hardware/database/locations.h
new file mode 100644
index 00000000..2ec56807
--- /dev/null
+++ b/WebApp/hardware/database/locations.h
@@ -0,0 +1,9 @@
+#ifndef ROOMS_LOCATIONS_H_
+#define ROOMS_LOCATIONS_H_
+//Will be a file of all the rooms on a given floor
+#define ROOM_1 101
+#define ROOM_2 102
+#define ROOM_3 103
+#define DATABASE 201 //room floor
+
+#endif //COUNTRY_ROADS_HARDWARE_LOCATIONS_H_
\ No newline at end of file
diff --git a/WebApp/hardware/database/messages.h b/WebApp/hardware/database/messages.h
new file mode 100644
index 00000000..68f276b1
--- /dev/null
+++ b/WebApp/hardware/database/messages.h
@@ -0,0 +1,35 @@
+#ifndef ROOMS_MESSAGES_H_
+#define ROOMS_MESSAGES_H_
+//Basic car structure
+//Needs to include Gerg's header from Hive Map
+//Contains: ID, Color, Heading, GasLevel, speed
+
+#include
+#include
+#include "locations.h"
+
+// message constants
+#define OCCUPANCY_MSG 12 //10 or higher
+
+namespace occupancy
+{
+
+struct Body //body of message containing occupancy state
+{
+ bool occupied = false;
+ unsigned char roomID = 0;
+};
+
+struct Msg
+{ //creating of a message that will be sent
+ hmap::msg::Header header{
+ .type = OCCUPANCY_MSG,
+ .bcast_radius = 1,
+ .destination = hmap::loc::ANY,
+ .size = sizeof(Msg)};
+ Body body;
+ unsigned char type = OCCUPANCY_MSG;
+};
+
+} // namespace occupancy
+#endif //COUNTRY_ROADS_HARDWARE_MESSAGES_H_
diff --git a/WebApp/hardware/database/radio_endpoint.h b/WebApp/hardware/database/radio_endpoint.h
new file mode 100644
index 00000000..3d246f25
--- /dev/null
+++ b/WebApp/hardware/database/radio_endpoint.h
@@ -0,0 +1,39 @@
+#ifndef FLOM_RADIO_ENDPOINT_H_
+#define FLOM_RADIO_ENDPOINT_H_
+//code to set up radio communication for the arduinos
+#include
+#include
+
+class RadioEndPoint : public hmap::network::non_blocking::EndPoint
+{
+public:
+ RadioEndPoint() : m_radio(7, 8) {}
+ void setup(const byte address[6])
+ {
+ m_radio.begin();
+ m_radio.openReadingPipe(0, address);
+ m_radio.openWritingPipe(address);
+ m_radio.startListening();
+ m_radio.setPALevel(RF24_PA_MIN);
+ }
+ void broadcast(char *data, size_t len) override
+ {
+ m_radio.stopListening();
+ m_radio.write(data, len);
+ m_radio.startListening();
+ }
+ size_t deliver(char *data, size_t len) override
+ {
+ if (m_radio.available())
+ {
+ m_radio.read(data, len);
+ return len;
+ }
+ return 0;
+ }
+
+private:
+ RF24 m_radio;
+};
+
+#endif
\ No newline at end of file
diff --git a/WebApp/hardware/room/.vscode/settings.json b/WebApp/hardware/room/.vscode/settings.json
new file mode 100644
index 00000000..41e87a38
--- /dev/null
+++ b/WebApp/hardware/room/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "C_Cpp.errorSquiggles": "Disabled"
+}
\ No newline at end of file
diff --git a/WebApp/hardware/room/locations.h b/WebApp/hardware/room/locations.h
new file mode 100644
index 00000000..08b84308
--- /dev/null
+++ b/WebApp/hardware/room/locations.h
@@ -0,0 +1,9 @@
+#ifndef ROOMS_LOCATIONS_H_
+#define ROOMS_LOCATIONS_H_
+
+#define ROOM_1 101
+#define ROOM_2 102
+#define ROOM_3 103
+#define DATABASE 201
+
+#endif //COUNTRY_ROADS_HARDWARE_LOCATIONS_H_
\ No newline at end of file
diff --git a/WebApp/hardware/room/messages.h b/WebApp/hardware/room/messages.h
new file mode 100644
index 00000000..84aad2b0
--- /dev/null
+++ b/WebApp/hardware/room/messages.h
@@ -0,0 +1,32 @@
+#ifndef ROOMS_MESSAGES_H_
+#define ROOMS_MESSAGES_H_
+//Basic car structure
+//Needs to include Gerg's header from Hive Map
+//Contains: ID, Color, Heading, GasLevel, speed
+
+#include
+#include
+#include "locations.h"
+
+// message constants
+#define OCCUPANCY_MSG 12 //10 or higher
+
+namespace occupancy {
+
+struct Body {
+ bool occupied = false;
+ unsigned char roomID = ROOM_1;
+};
+
+struct Msg{
+ hmap::msg::Header header {
+ .type = OCCUPANCY_MSG,
+ .bcast_radius = 1,
+ .destination = hmap::loc::ANY,
+ .size = sizeof(Msg)
+ };
+ Body body;
+};
+
+}
+#endif //COUNTRY_ROADS_HARDWARE_MESSAGES_H_
diff --git a/WebApp/hardware/room/radio_endpoint.h b/WebApp/hardware/room/radio_endpoint.h
new file mode 100644
index 00000000..cbb2b2b7
--- /dev/null
+++ b/WebApp/hardware/room/radio_endpoint.h
@@ -0,0 +1,34 @@
+#ifndef FLOM_RADIO_ENDPOINT_H_
+#define FLOM_RADIO_ENDPOINT_H_
+
+#include
+#include
+
+class RadioEndPoint: public hmap::network::non_blocking::EndPoint {
+public:
+ RadioEndPoint():
+ m_radio(7, 8){ }
+ void setup(const byte address[6]) {
+ m_radio.begin();
+ m_radio.openReadingPipe(0,address);
+ m_radio.openWritingPipe(address);
+ m_radio.startListening();
+ m_radio.setPALevel(RF24_PA_MIN);
+ }
+ void broadcast(char* data, size_t len) override {
+ m_radio.stopListening();
+ m_radio.write(data, len);
+ m_radio.startListening();
+ }
+ size_t deliver(char* data, size_t len) override{
+ if(m_radio.available()){
+ m_radio.read(data, len);
+ return len;
+ }
+ return 0;
+ }
+private:
+ RF24 m_radio;
+};
+
+#endif
\ No newline at end of file
diff --git a/WebApp/hardware/room/room.ino b/WebApp/hardware/room/room.ino
new file mode 100644
index 00000000..555cbe02
--- /dev/null
+++ b/WebApp/hardware/room/room.ino
@@ -0,0 +1,124 @@
+#include
+#include "radio_endpoint.h"
+#include "messages.h"
+#include "locations.h"
+
+#define analogPin 8
+
+hmap::Location room(ROOM_1);
+RadioEndPoint radio_endpoint;
+occupancy::Msg occupancy_msg;
+const byte address[6] = "00001";
+
+int val;
+
+void setup()
+{
+ radio_endpoint.setup(address);
+ Serial.begin(9600);
+ occupancy_msg.body.occupied = false; //not occupied
+ occupancy_msg.body.roomID = ROOM_1; //room 101
+ room.bind(radio_endpoint);
+}
+
+const unsigned int cycle_delay = 250;
+const unsigned int publish_delay_ratio = 4;
+unsigned int publish_count = 0;
+
+void loop()
+{
+ delay(cycle_delay);
+ // Read "data" from potentiometers
+ /*
+
+ */
+ val = analogRead(analogPin);
+ if (val < 128) {
+ occupancy_msg.body.occupied = true;
+ }
+ else {
+ occupancy_msg.body.occupied = false;
+ }
+ if ((publish_count % publish_delay_ratio) == 0)
+ {
+ room.destinations(DATABASE).publish(occupancy_msg);
+ }
+ room.cycle();
+ ++publish_count;
+}
+
+/*
+#include "hive_map.h"
+#include "hive_map.c"
+
+#define PIR 2 //connect PIR sensor to pin 2 of arduino
+#define LED 13 //connect LED for testing
+
+int PIR_STATE = LOW;
+int val = 0;
+byte timer = 0;
+bool cycle_flag = true;
+
+typedef struct Occupancy_Space { //creating an occupancy space
+ HiveMapSpaceId space;
+ bool isOccupied;
+} Occupancy_Space;
+
+HiveMapNode(Occupancy_Space) node; //room defined by occupancy space
+
+void setup_interrupts() {
+ noInterrupts(); // disable interrupts
+ // set up timer interput phase
+ TCCR1A = 0;
+ TCCR1B = 0;
+ TCNT1 = 0;
+ OCR1A = 31250; // compare match register (16MHz/256/2Hz)
+ TCCR1B |= (1 << WGM12); // CTC mode
+ TCCR1B |= (1 << CS12); // 256 prescaler
+ TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
+ interrupts(); // re-endable interrupts
+}
+
+ISR(TIMER1_COMPA_vect)
+{
+ TCNT1 = 34286; // timer duration
+ cycle_flag = true;
+ ++timer;
+}
+
+void setup(){
+ pinMode(LED, OUTPUT);
+ pinMode(PIR, INPUT);
+ setup_interrupts();
+ node.loc = 10; //room number
+ node.goal_loc = 1; //floor number
+ node.state_received = NULL;
+ Serial.begin(9600);
+}
+
+void loop(){
+ val = digitalRead(PIR);
+ if (val == HIGH) { // check if the input is HIGH
+ digitalWrite(LED, HIGH); // turn LED ON
+ if (PIR_STATE == LOW) {
+ Serial.println("Motion detected!");
+ PIR_STATE = HIGH;
+ node.state.isOccupied = true;
+ update_node(&node, sizeof(node)); //update node
+ }
+ }
+ else {
+ digitalWrite(LED, LOW); // turn LED OFF
+ if (PIR_STATE == HIGH){
+ Serial.println("Motion ended!");
+ PIR_STATE = LOW;
+ node.state.isOccupied = false;
+ update_node(&node, sizeof(node));
+ }
+ }
+ if(cycle_flag) {
+ cycle_node(&node, sizeof(node));
+ cycle_flag = false;
+ }
+}
+*/
diff --git a/_software/manage.py b/WebApp/manage.py
old mode 100755
new mode 100644
similarity index 72%
rename from _software/manage.py
rename to WebApp/manage.py
index d15201a8..a9d27c72
--- a/_software/manage.py
+++ b/WebApp/manage.py
@@ -1,15 +1,21 @@
-#!/usr/bin/env python
-import os
-import sys
-
-if __name__ == '__main__':
- os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'flom.settings')
- try:
- from django.core.management import execute_from_command_line
- except ImportError as exc:
- raise ImportError(
- "Couldn't import Django. Are you sure it's installed and "
- "available on your PYTHONPATH environment variable? Did you "
- "forget to activate a virtual environment?"
- ) from exc
- execute_from_command_line(sys.argv)
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'WebApp.settings')
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/_software/static/styles/main.css b/WebApp/static/css/main.css
similarity index 73%
rename from _software/static/styles/main.css
rename to WebApp/static/css/main.css
index 72abdd37..ff5577b0 100644
--- a/_software/static/styles/main.css
+++ b/WebApp/static/css/main.css
@@ -1,22 +1,22 @@
-/*
- Main styles
- */
-
-html {
- font-family: "Segoe UI Semibold", sans-serif;
- color: #ffffff;
-}
-
-body {
- background: linear-gradient(to left, #3e3e3f, #2d2d2e);
-}
-
-.about {
- background-color: white;
- margin: 10px;
- padding: 10px;
-}
-
-.stats_table {
- padding: 100px;
-}
+/*
+ Main styles
+ */
+
+html {
+ font-family: "Segoe UI Semibold", sans-serif;
+ color: #ffffff;
+}
+
+body {
+ background: linear-gradient(to left, #3e3e3f, #2ded2e);
+}
+
+.about {
+ background-color: white;
+ margin: 10px;
+ padding: 10px;
+}
+
+.stats_table {
+ padding: 100px;
+}
diff --git a/_software/library_monitor/static/library_monitor/styles/map.css b/WebApp/static/css/map.css
similarity index 90%
rename from _software/library_monitor/static/library_monitor/styles/map.css
rename to WebApp/static/css/map.css
index 6e6694d5..16a2bf8c 100644
--- a/_software/library_monitor/static/library_monitor/styles/map.css
+++ b/WebApp/static/css/map.css
@@ -1,18 +1,19 @@
-/*
-Styles for the floor plans
- */
-
-.map {
- display: block;
- position: absolute;
- margin-left: auto;
- margin-right: auto;
- width: 60%;
- top: 15%;
- left: 20%;
- z-index: -1;
-}
-
-#floor-plan {
- z-index: -2;
-}
\ No newline at end of file
+
+/*
+Styles for the floor plans
+ */
+
+.map {
+ display: block;
+ position: absolute;
+ margin-left: auto;
+ margin-right: auto;
+ width: 60%;
+ top: 15%;
+ left: 20%;
+ z-index: -1;
+}
+
+#floor-plan {
+ z-index: -2;
+}
diff --git a/_software/library_monitor/static/library_monitor/styles/navbar.css b/WebApp/static/css/navbar.css
similarity index 91%
rename from _software/library_monitor/static/library_monitor/styles/navbar.css
rename to WebApp/static/css/navbar.css
index b0fc5ac8..8ae5c678 100644
--- a/_software/library_monitor/static/library_monitor/styles/navbar.css
+++ b/WebApp/static/css/navbar.css
@@ -1,7 +1,8 @@
-/*
- Styles for the navigation bar widget
- */
-
-.main-menu {
- margin: 0px 10px 0px 10px;
-}
+
+/*
+ Styles for the navigation bar widget
+ */
+
+.main-menu {
+ margin: 0px 10px 0px 10px;
+}
diff --git a/WebApp/static/css/style.css b/WebApp/static/css/style.css
new file mode 100644
index 00000000..a0a6fcae
--- /dev/null
+++ b/WebApp/static/css/style.css
@@ -0,0 +1,240 @@
+html {
+ font-family:'IBM Plex Sans', sans-serif !important;
+}
+
+body{
+ /* RED BACKGROUND */
+ background-color: #b3252c;
+}
+
+.home-bg {
+ background-color: white;
+}
+
+.navbar{
+ font-size: 18.5px;
+ margin: 0px 0px 0px 0px;
+ /* background-color: #092638; */
+}
+
+.dropdown {
+ position: relative;
+ display: inline-block;
+}
+
+.dropdown-content {
+ display: none;
+ position: absolute;
+ background-color: #ffffff;
+ min-width: 160px;
+ box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
+ z-index: 1;
+}
+
+ color: black;
+.dropdown-content a {
+ padding: 12px 16px;
+ text-decoration: none;
+ display: block;
+}
+
+.dropdown-content a:hover {background-color: #f1f1f1}
+
+.dropdown:hover .dropdown-content {
+ display: block;
+}
+
+.dropdown:hover .dropbtn {
+ background-color: #7e8e41;
+}
+
+/* when hovering, changes background to gray */
+.gray a {
+ background-image: linear-gradient(to right, rgba(255,255,255,0) 50%, rgba(210, 215, 811, 1) 50%);
+ background-position: -0% 0;
+ background-size: 200% auto;
+ color: #222;
+ line-height: 1em;
+ /* text-decoration-color: #D7D9D7; */
+ transition: background-position .6s ease-out;
+}
+
+a:hover {
+ background-position: -99.99% 0;
+ /* background-color: #28577B; */
+}
+
+/* ABOUT PAGE STYLING - non-hover image area*/
+.about {
+ background-color: white;
+ margin: 10px;
+ padding: 10px;
+ border-radius: 5px;
+ margin-left: 12%;
+ margin-right: 12%;
+ position: relative;
+ height: auto;
+}
+
+.container {
+ background-color: rgba(255, 0, 0, 0.0) !important;
+}
+
+.image {
+ display: block;
+ margin: auto;
+ width: 95%;
+ height: auto;
+ border-radius: 5px;
+ padding-bottom: 30px;
+ padding-top: 30px;
+}
+/* HOVER OVER LIBRARY IMAGE */
+.overlay {
+ margin: auto;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: white;
+ overflow: hidden;
+ width: 95%;
+ height:100%;
+ opacity: 0;
+ transition: .5s ease;
+ border-radius: 5px;
+}
+/* The actual hover event that triggers the text to appear */
+.about:hover .overlay {
+ opacity:1;
+}
+/* how the text is displayed inside the overlay */
+.text {
+ font-size: 0.9vw; /* responsive text size is 0.9% of the viewport */
+ position: relative;
+ top: 25%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -25%);
+ -ms-transform: translate(-50%, -25%);
+ transform: translate(-50%, -25%);
+ text-align: center;
+ font-weight: bold;
+ padding-left: 20%;
+ padding-right: 20%; /* paddings keep text pushed in center */
+}
+/* based on the size of the screen, change how the
+text is disaplyed as well as the size of the bow its in */
+@media screen and (max-width: 991px){
+ .text{
+ padding: 1px;
+ }
+ .about{
+ height:400px;
+ }
+}
+
+
+.fixed-arrow {
+ position: absolute;
+ bottom: 25px;
+ left: 49%;
+ align: center;
+}
+
+div .landing {
+ height: 100vh;
+}
+
+.big {
+ font-size: 20px;
+}
+
+.footer {
+ font-size: 12px;
+ color: #092638;
+ margin-bottom: 50px;
+}
+
+.center {
+ text-align: center;
+ text-decoration-color: #D7D9D7;
+}
+
+.stats_table {
+ padding: 100px;
+}
+
+/* LOGIN PAGE CSSS */
+.login-main{
+ position: relative;
+ top: 10%;
+ background-color: white;
+ display: block;
+ border-radius: 5px;
+ margin: auto;
+ text-align: center;
+ width: 50%;
+ padding: 10px;
+}
+
+.login-img {
+ margin: auto;
+ width: 55%;
+ padding: 10px;
+}
+
+.login-sub{
+ background-color: #b3252c;
+ border: none;
+ color: white;
+ font-weight: bold;
+ padding: 10px 27px;
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ font-size: 16px;
+ margin: 4px 3px;
+ cursor: pointer;
+ border-radius: 50px;
+ text-decoration: none;
+}
+.login-sub:hover {
+ box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19);
+}
+/* LOGOUT PAGE CSS */
+.logout {
+ background-color: white;
+ color: #b3252c;
+ padding: 50px;
+ margin: auto;
+ width: 50%;
+ margin-top: 50px;
+ text-align: center;
+ border-radius: 5px;
+}
+
+/* STATS PAGE CSS */
+table {
+ border-collapse: collapse;
+ width: 100%;
+}
+
+th, td {
+ text-align: left;
+ padding: 8px;
+}
+
+td {
+ background-color: #c1c1c1;
+}
+
+th {
+ background-color: #f1f1f1;
+ color: black;
+ text-shadow: 2px;
+}
+
+.table-form-request {
+ text-align: center;
+}
\ No newline at end of file
diff --git a/WebApp/static/scripts/jquery-3.3.1.min.js b/WebApp/static/scripts/jquery-3.3.1.min.js
new file mode 100644
index 00000000..bdfaaf0b
--- /dev/null
+++ b/WebApp/static/scripts/jquery-3.3.1.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license
+ Drop Down Menu Script
+*/
+!function (e, t) { "use strict"; "object" == typeof module && "object" == typeof module.exports ? module.exports = e.document ? t(e, !0) : function (e) { if (!e.document) throw new Error("jQuery requires a window with a document"); return t(e) } : t(e) }("undefined" != typeof window ? window : this, function (e, t) { "use strict"; var n = [], r = e.document, i = Object.getPrototypeOf, o = n.slice, a = n.concat, s = n.push, u = n.indexOf, l = {}, c = l.toString, f = l.hasOwnProperty, p = f.toString, d = p.call(Object), h = {}, g = function e(t) { return "function" == typeof t && "number" != typeof t.nodeType }, y = function e(t) { return null != t && t === t.window }, v = { type: !0, src: !0, noModule: !0 }; function m(e, t, n) { var i, o = (t = t || r).createElement("script"); if (o.text = e, n) for (i in v) n[i] && (o[i] = n[i]); t.head.appendChild(o).parentNode.removeChild(o) } function x(e) { return null == e ? e + "" : "object" == typeof e || "function" == typeof e ? l[c.call(e)] || "object" : typeof e } var b = "3.3.1", w = function (e, t) { return new w.fn.init(e, t) }, T = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; w.fn = w.prototype = { jquery: "3.3.1", constructor: w, length: 0, toArray: function () { return o.call(this) }, get: function (e) { return null == e ? o.call(this) : e < 0 ? this[e + this.length] : this[e] }, pushStack: function (e) { var t = w.merge(this.constructor(), e); return t.prevObject = this, t }, each: function (e) { return w.each(this, e) }, map: function (e) { return this.pushStack(w.map(this, function (t, n) { return e.call(t, n, t) })) }, slice: function () { return this.pushStack(o.apply(this, arguments)) }, first: function () { return this.eq(0) }, last: function () { return this.eq(-1) }, eq: function (e) { var t = this.length, n = +e + (e < 0 ? t : 0); return this.pushStack(n >= 0 && n < t ? [this[n]] : []) }, end: function () { return this.prevObject || this.constructor() }, push: s, sort: n.sort, splice: n.splice }, w.extend = w.fn.extend = function () { var e, t, n, r, i, o, a = arguments[0] || {}, s = 1, u = arguments.length, l = !1; for ("boolean" == typeof a && (l = a, a = arguments[s] || {}, s++), "object" == typeof a || g(a) || (a = {}), s === u && (a = this, s--); s < u; s++)if (null != (e = arguments[s])) for (t in e) n = a[t], a !== (r = e[t]) && (l && r && (w.isPlainObject(r) || (i = Array.isArray(r))) ? (i ? (i = !1, o = n && Array.isArray(n) ? n : []) : o = n && w.isPlainObject(n) ? n : {}, a[t] = w.extend(l, o, r)) : void 0 !== r && (a[t] = r)); return a }, w.extend({ expando: "jQuery" + ("3.3.1" + Math.random()).replace(/\D/g, ""), isReady: !0, error: function (e) { throw new Error(e) }, noop: function () { }, isPlainObject: function (e) { var t, n; return !(!e || "[object Object]" !== c.call(e)) && (!(t = i(e)) || "function" == typeof (n = f.call(t, "constructor") && t.constructor) && p.call(n) === d) }, isEmptyObject: function (e) { var t; for (t in e) return !1; return !0 }, globalEval: function (e) { m(e) }, each: function (e, t) { var n, r = 0; if (C(e)) { for (n = e.length; r < n; r++)if (!1 === t.call(e[r], r, e[r])) break } else for (r in e) if (!1 === t.call(e[r], r, e[r])) break; return e }, trim: function (e) { return null == e ? "" : (e + "").replace(T, "") }, makeArray: function (e, t) { var n = t || []; return null != e && (C(Object(e)) ? w.merge(n, "string" == typeof e ? [e] : e) : s.call(n, e)), n }, inArray: function (e, t, n) { return null == t ? -1 : u.call(t, e, n) }, merge: function (e, t) { for (var n = +t.length, r = 0, i = e.length; r < n; r++)e[i++] = t[r]; return e.length = i, e }, grep: function (e, t, n) { for (var r, i = [], o = 0, a = e.length, s = !n; o < a; o++)(r = !t(e[o], o)) !== s && i.push(e[o]); return i }, map: function (e, t, n) { var r, i, o = 0, s = []; if (C(e)) for (r = e.length; o < r; o++)null != (i = t(e[o], o, n)) && s.push(i); else for (o in e) null != (i = t(e[o], o, n)) && s.push(i); return a.apply([], s) }, guid: 1, support: h }), "function" == typeof Symbol && (w.fn[Symbol.iterator] = n[Symbol.iterator]), w.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "), function (e, t) { l["[object " + t + "]"] = t.toLowerCase() }); function C(e) { var t = !!e && "length" in e && e.length, n = x(e); return !g(e) && !y(e) && ("array" === n || 0 === t || "number" == typeof t && t > 0 && t - 1 in e) } var E = function (e) { var t, n, r, i, o, a, s, u, l, c, f, p, d, h, g, y, v, m, x, b = "sizzle" + 1 * new Date, w = e.document, T = 0, C = 0, E = ae(), k = ae(), S = ae(), D = function (e, t) { return e === t && (f = !0), 0 }, N = {}.hasOwnProperty, A = [], j = A.pop, q = A.push, L = A.push, H = A.slice, O = function (e, t) { for (var n = 0, r = e.length; n < r; n++)if (e[n] === t) return n; return -1 }, P = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", M = "[\\x20\\t\\r\\n\\f]", R = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", I = "\\[" + M + "*(" + R + ")(?:" + M + "*([*^$|!~]?=)" + M + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + R + "))|)" + M + "*\\]", W = ":(" + R + ")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|" + I + ")*)|.*)\\)|)", $ = new RegExp(M + "+", "g"), B = new RegExp("^" + M + "+|((?:^|[^\\\\])(?:\\\\.)*)" + M + "+$", "g"), F = new RegExp("^" + M + "*," + M + "*"), _ = new RegExp("^" + M + "*([>+~]|" + M + ")" + M + "*"), z = new RegExp("=" + M + "*([^\\]'\"]*?)" + M + "*\\]", "g"), X = new RegExp(W), U = new RegExp("^" + R + "$"), V = { ID: new RegExp("^#(" + R + ")"), CLASS: new RegExp("^\\.(" + R + ")"), TAG: new RegExp("^(" + R + "|[*])"), ATTR: new RegExp("^" + I), PSEUDO: new RegExp("^" + W), CHILD: new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + M + "*(even|odd|(([+-]|)(\\d*)n|)" + M + "*(?:([+-]|)" + M + "*(\\d+)|))" + M + "*\\)|)", "i"), bool: new RegExp("^(?:" + P + ")$", "i"), needsContext: new RegExp("^" + M + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + M + "*((?:-\\d)?\\d*)" + M + "*\\)|)(?=[^-]|$)", "i") }, G = /^(?:input|select|textarea|button)$/i, Y = /^h\d$/i, Q = /^[^{]+\{\s*\[native \w/, J = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, K = /[+~]/, Z = new RegExp("\\\\([\\da-f]{1,6}" + M + "?|(" + M + ")|.)", "ig"), ee = function (e, t, n) { var r = "0x" + t - 65536; return r !== r || n ? t : r < 0 ? String.fromCharCode(r + 65536) : String.fromCharCode(r >> 10 | 55296, 1023 & r | 56320) }, te = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, ne = function (e, t) { return t ? "\0" === e ? "\ufffd" : e.slice(0, -1) + "\\" + e.charCodeAt(e.length - 1).toString(16) + " " : "\\" + e }, re = function () { p() }, ie = me(function (e) { return !0 === e.disabled && ("form" in e || "label" in e) }, { dir: "parentNode", next: "legend" }); try { L.apply(A = H.call(w.childNodes), w.childNodes), A[w.childNodes.length].nodeType } catch (e) { L = { apply: A.length ? function (e, t) { q.apply(e, H.call(t)) } : function (e, t) { var n = e.length, r = 0; while (e[n++] = t[r++]); e.length = n - 1 } } } function oe(e, t, r, i) { var o, s, l, c, f, h, v, m = t && t.ownerDocument, T = t ? t.nodeType : 9; if (r = r || [], "string" != typeof e || !e || 1 !== T && 9 !== T && 11 !== T) return r; if (!i && ((t ? t.ownerDocument || t : w) !== d && p(t), t = t || d, g)) { if (11 !== T && (f = J.exec(e))) if (o = f[1]) { if (9 === T) { if (!(l = t.getElementById(o))) return r; if (l.id === o) return r.push(l), r } else if (m && (l = m.getElementById(o)) && x(t, l) && l.id === o) return r.push(l), r } else { if (f[2]) return L.apply(r, t.getElementsByTagName(e)), r; if ((o = f[3]) && n.getElementsByClassName && t.getElementsByClassName) return L.apply(r, t.getElementsByClassName(o)), r } if (n.qsa && !S[e + " "] && (!y || !y.test(e))) { if (1 !== T) m = t, v = e; else if ("object" !== t.nodeName.toLowerCase()) { (c = t.getAttribute("id")) ? c = c.replace(te, ne) : t.setAttribute("id", c = b), s = (h = a(e)).length; while (s--) h[s] = "#" + c + " " + ve(h[s]); v = h.join(","), m = K.test(e) && ge(t.parentNode) || t } if (v) try { return L.apply(r, m.querySelectorAll(v)), r } catch (e) { } finally { c === b && t.removeAttribute("id") } } } return u(e.replace(B, "$1"), t, r, i) } function ae() { var e = []; function t(n, i) { return e.push(n + " ") > r.cacheLength && delete t[e.shift()], t[n + " "] = i } return t } function se(e) { return e[b] = !0, e } function ue(e) { var t = d.createElement("fieldset"); try { return !!e(t) } catch (e) { return !1 } finally { t.parentNode && t.parentNode.removeChild(t), t = null } } function le(e, t) { var n = e.split("|"), i = n.length; while (i--) r.attrHandle[n[i]] = t } function ce(e, t) { var n = t && e, r = n && 1 === e.nodeType && 1 === t.nodeType && e.sourceIndex - t.sourceIndex; if (r) return r; if (n) while (n = n.nextSibling) if (n === t) return -1; return e ? 1 : -1 } function fe(e) { return function (t) { return "input" === t.nodeName.toLowerCase() && t.type === e } } function pe(e) { return function (t) { var n = t.nodeName.toLowerCase(); return ("input" === n || "button" === n) && t.type === e } } function de(e) { return function (t) { return "form" in t ? t.parentNode && !1 === t.disabled ? "label" in t ? "label" in t.parentNode ? t.parentNode.disabled === e : t.disabled === e : t.isDisabled === e || t.isDisabled !== !e && ie(t) === e : t.disabled === e : "label" in t && t.disabled === e } } function he(e) { return se(function (t) { return t = +t, se(function (n, r) { var i, o = e([], n.length, t), a = o.length; while (a--) n[i = o[a]] && (n[i] = !(r[i] = n[i])) }) }) } function ge(e) { return e && "undefined" != typeof e.getElementsByTagName && e } n = oe.support = {}, o = oe.isXML = function (e) { var t = e && (e.ownerDocument || e).documentElement; return !!t && "HTML" !== t.nodeName }, p = oe.setDocument = function (e) { var t, i, a = e ? e.ownerDocument || e : w; return a !== d && 9 === a.nodeType && a.documentElement ? (d = a, h = d.documentElement, g = !o(d), w !== d && (i = d.defaultView) && i.top !== i && (i.addEventListener ? i.addEventListener("unload", re, !1) : i.attachEvent && i.attachEvent("onunload", re)), n.attributes = ue(function (e) { return e.className = "i", !e.getAttribute("className") }), n.getElementsByTagName = ue(function (e) { return e.appendChild(d.createComment("")), !e.getElementsByTagName("*").length }), n.getElementsByClassName = Q.test(d.getElementsByClassName), n.getById = ue(function (e) { return h.appendChild(e).id = b, !d.getElementsByName || !d.getElementsByName(b).length }), n.getById ? (r.filter.ID = function (e) { var t = e.replace(Z, ee); return function (e) { return e.getAttribute("id") === t } }, r.find.ID = function (e, t) { if ("undefined" != typeof t.getElementById && g) { var n = t.getElementById(e); return n ? [n] : [] } }) : (r.filter.ID = function (e) { var t = e.replace(Z, ee); return function (e) { var n = "undefined" != typeof e.getAttributeNode && e.getAttributeNode("id"); return n && n.value === t } }, r.find.ID = function (e, t) { if ("undefined" != typeof t.getElementById && g) { var n, r, i, o = t.getElementById(e); if (o) { if ((n = o.getAttributeNode("id")) && n.value === e) return [o]; i = t.getElementsByName(e), r = 0; while (o = i[r++]) if ((n = o.getAttributeNode("id")) && n.value === e) return [o] } return [] } }), r.find.TAG = n.getElementsByTagName ? function (e, t) { return "undefined" != typeof t.getElementsByTagName ? t.getElementsByTagName(e) : n.qsa ? t.querySelectorAll(e) : void 0 } : function (e, t) { var n, r = [], i = 0, o = t.getElementsByTagName(e); if ("*" === e) { while (n = o[i++]) 1 === n.nodeType && r.push(n); return r } return o }, r.find.CLASS = n.getElementsByClassName && function (e, t) { if ("undefined" != typeof t.getElementsByClassName && g) return t.getElementsByClassName(e) }, v = [], y = [], (n.qsa = Q.test(d.querySelectorAll)) && (ue(function (e) { h.appendChild(e).innerHTML = " ", e.querySelectorAll("[msallowcapture^='']").length && y.push("[*^$]=" + M + "*(?:''|\"\")"), e.querySelectorAll("[selected]").length || y.push("\\[" + M + "*(?:value|" + P + ")"), e.querySelectorAll("[id~=" + b + "-]").length || y.push("~="), e.querySelectorAll(":checked").length || y.push(":checked"), e.querySelectorAll("a#" + b + "+*").length || y.push(".#.+[+~]") }), ue(function (e) { e.innerHTML = " "; var t = d.createElement("input"); t.setAttribute("type", "hidden"), e.appendChild(t).setAttribute("name", "D"), e.querySelectorAll("[name=d]").length && y.push("name" + M + "*[*^$|!~]?="), 2 !== e.querySelectorAll(":enabled").length && y.push(":enabled", ":disabled"), h.appendChild(e).disabled = !0, 2 !== e.querySelectorAll(":disabled").length && y.push(":enabled", ":disabled"), e.querySelectorAll("*,:x"), y.push(",.*:") })), (n.matchesSelector = Q.test(m = h.matches || h.webkitMatchesSelector || h.mozMatchesSelector || h.oMatchesSelector || h.msMatchesSelector)) && ue(function (e) { n.disconnectedMatch = m.call(e, "*"), m.call(e, "[s!='']:x"), v.push("!=", W) }), y = y.length && new RegExp(y.join("|")), v = v.length && new RegExp(v.join("|")), t = Q.test(h.compareDocumentPosition), x = t || Q.test(h.contains) ? function (e, t) { var n = 9 === e.nodeType ? e.documentElement : e, r = t && t.parentNode; return e === r || !(!r || 1 !== r.nodeType || !(n.contains ? n.contains(r) : e.compareDocumentPosition && 16 & e.compareDocumentPosition(r))) } : function (e, t) { if (t) while (t = t.parentNode) if (t === e) return !0; return !1 }, D = t ? function (e, t) { if (e === t) return f = !0, 0; var r = !e.compareDocumentPosition - !t.compareDocumentPosition; return r || (1 & (r = (e.ownerDocument || e) === (t.ownerDocument || t) ? e.compareDocumentPosition(t) : 1) || !n.sortDetached && t.compareDocumentPosition(e) === r ? e === d || e.ownerDocument === w && x(w, e) ? -1 : t === d || t.ownerDocument === w && x(w, t) ? 1 : c ? O(c, e) - O(c, t) : 0 : 4 & r ? -1 : 1) } : function (e, t) { if (e === t) return f = !0, 0; var n, r = 0, i = e.parentNode, o = t.parentNode, a = [e], s = [t]; if (!i || !o) return e === d ? -1 : t === d ? 1 : i ? -1 : o ? 1 : c ? O(c, e) - O(c, t) : 0; if (i === o) return ce(e, t); n = e; while (n = n.parentNode) a.unshift(n); n = t; while (n = n.parentNode) s.unshift(n); while (a[r] === s[r]) r++; return r ? ce(a[r], s[r]) : a[r] === w ? -1 : s[r] === w ? 1 : 0 }, d) : d }, oe.matches = function (e, t) { return oe(e, null, null, t) }, oe.matchesSelector = function (e, t) { if ((e.ownerDocument || e) !== d && p(e), t = t.replace(z, "='$1']"), n.matchesSelector && g && !S[t + " "] && (!v || !v.test(t)) && (!y || !y.test(t))) try { var r = m.call(e, t); if (r || n.disconnectedMatch || e.document && 11 !== e.document.nodeType) return r } catch (e) { } return oe(t, d, null, [e]).length > 0 }, oe.contains = function (e, t) { return (e.ownerDocument || e) !== d && p(e), x(e, t) }, oe.attr = function (e, t) { (e.ownerDocument || e) !== d && p(e); var i = r.attrHandle[t.toLowerCase()], o = i && N.call(r.attrHandle, t.toLowerCase()) ? i(e, t, !g) : void 0; return void 0 !== o ? o : n.attributes || !g ? e.getAttribute(t) : (o = e.getAttributeNode(t)) && o.specified ? o.value : null }, oe.escape = function (e) { return (e + "").replace(te, ne) }, oe.error = function (e) { throw new Error("Syntax error, unrecognized expression: " + e) }, oe.uniqueSort = function (e) { var t, r = [], i = 0, o = 0; if (f = !n.detectDuplicates, c = !n.sortStable && e.slice(0), e.sort(D), f) { while (t = e[o++]) t === e[o] && (i = r.push(o)); while (i--) e.splice(r[i], 1) } return c = null, e }, i = oe.getText = function (e) { var t, n = "", r = 0, o = e.nodeType; if (o) { if (1 === o || 9 === o || 11 === o) { if ("string" == typeof e.textContent) return e.textContent; for (e = e.firstChild; e; e = e.nextSibling)n += i(e) } else if (3 === o || 4 === o) return e.nodeValue } else while (t = e[r++]) n += i(t); return n }, (r = oe.selectors = { cacheLength: 50, createPseudo: se, match: V, attrHandle: {}, find: {}, relative: { ">": { dir: "parentNode", first: !0 }, " ": { dir: "parentNode" }, "+": { dir: "previousSibling", first: !0 }, "~": { dir: "previousSibling" } }, preFilter: { ATTR: function (e) { return e[1] = e[1].replace(Z, ee), e[3] = (e[3] || e[4] || e[5] || "").replace(Z, ee), "~=" === e[2] && (e[3] = " " + e[3] + " "), e.slice(0, 4) }, CHILD: function (e) { return e[1] = e[1].toLowerCase(), "nth" === e[1].slice(0, 3) ? (e[3] || oe.error(e[0]), e[4] = +(e[4] ? e[5] + (e[6] || 1) : 2 * ("even" === e[3] || "odd" === e[3])), e[5] = +(e[7] + e[8] || "odd" === e[3])) : e[3] && oe.error(e[0]), e }, PSEUDO: function (e) { var t, n = !e[6] && e[2]; return V.CHILD.test(e[0]) ? null : (e[3] ? e[2] = e[4] || e[5] || "" : n && X.test(n) && (t = a(n, !0)) && (t = n.indexOf(")", n.length - t) - n.length) && (e[0] = e[0].slice(0, t), e[2] = n.slice(0, t)), e.slice(0, 3)) } }, filter: { TAG: function (e) { var t = e.replace(Z, ee).toLowerCase(); return "*" === e ? function () { return !0 } : function (e) { return e.nodeName && e.nodeName.toLowerCase() === t } }, CLASS: function (e) { var t = E[e + " "]; return t || (t = new RegExp("(^|" + M + ")" + e + "(" + M + "|$)")) && E(e, function (e) { return t.test("string" == typeof e.className && e.className || "undefined" != typeof e.getAttribute && e.getAttribute("class") || "") }) }, ATTR: function (e, t, n) { return function (r) { var i = oe.attr(r, e); return null == i ? "!=" === t : !t || (i += "", "=" === t ? i === n : "!=" === t ? i !== n : "^=" === t ? n && 0 === i.indexOf(n) : "*=" === t ? n && i.indexOf(n) > -1 : "$=" === t ? n && i.slice(-n.length) === n : "~=" === t ? (" " + i.replace($, " ") + " ").indexOf(n) > -1 : "|=" === t && (i === n || i.slice(0, n.length + 1) === n + "-")) } }, CHILD: function (e, t, n, r, i) { var o = "nth" !== e.slice(0, 3), a = "last" !== e.slice(-4), s = "of-type" === t; return 1 === r && 0 === i ? function (e) { return !!e.parentNode } : function (t, n, u) { var l, c, f, p, d, h, g = o !== a ? "nextSibling" : "previousSibling", y = t.parentNode, v = s && t.nodeName.toLowerCase(), m = !u && !s, x = !1; if (y) { if (o) { while (g) { p = t; while (p = p[g]) if (s ? p.nodeName.toLowerCase() === v : 1 === p.nodeType) return !1; h = g = "only" === e && !h && "nextSibling" } return !0 } if (h = [a ? y.firstChild : y.lastChild], a && m) { x = (d = (l = (c = (f = (p = y)[b] || (p[b] = {}))[p.uniqueID] || (f[p.uniqueID] = {}))[e] || [])[0] === T && l[1]) && l[2], p = d && y.childNodes[d]; while (p = ++d && p && p[g] || (x = d = 0) || h.pop()) if (1 === p.nodeType && ++x && p === t) { c[e] = [T, d, x]; break } } else if (m && (x = d = (l = (c = (f = (p = t)[b] || (p[b] = {}))[p.uniqueID] || (f[p.uniqueID] = {}))[e] || [])[0] === T && l[1]), !1 === x) while (p = ++d && p && p[g] || (x = d = 0) || h.pop()) if ((s ? p.nodeName.toLowerCase() === v : 1 === p.nodeType) && ++x && (m && ((c = (f = p[b] || (p[b] = {}))[p.uniqueID] || (f[p.uniqueID] = {}))[e] = [T, x]), p === t)) break; return (x -= i) === r || x % r == 0 && x / r >= 0 } } }, PSEUDO: function (e, t) { var n, i = r.pseudos[e] || r.setFilters[e.toLowerCase()] || oe.error("unsupported pseudo: " + e); return i[b] ? i(t) : i.length > 1 ? (n = [e, e, "", t], r.setFilters.hasOwnProperty(e.toLowerCase()) ? se(function (e, n) { var r, o = i(e, t), a = o.length; while (a--) e[r = O(e, o[a])] = !(n[r] = o[a]) }) : function (e) { return i(e, 0, n) }) : i } }, pseudos: { not: se(function (e) { var t = [], n = [], r = s(e.replace(B, "$1")); return r[b] ? se(function (e, t, n, i) { var o, a = r(e, null, i, []), s = e.length; while (s--) (o = a[s]) && (e[s] = !(t[s] = o)) }) : function (e, i, o) { return t[0] = e, r(t, null, o, n), t[0] = null, !n.pop() } }), has: se(function (e) { return function (t) { return oe(e, t).length > 0 } }), contains: se(function (e) { return e = e.replace(Z, ee), function (t) { return (t.textContent || t.innerText || i(t)).indexOf(e) > -1 } }), lang: se(function (e) { return U.test(e || "") || oe.error("unsupported lang: " + e), e = e.replace(Z, ee).toLowerCase(), function (t) { var n; do { if (n = g ? t.lang : t.getAttribute("xml:lang") || t.getAttribute("lang")) return (n = n.toLowerCase()) === e || 0 === n.indexOf(e + "-") } while ((t = t.parentNode) && 1 === t.nodeType); return !1 } }), target: function (t) { var n = e.location && e.location.hash; return n && n.slice(1) === t.id }, root: function (e) { return e === h }, focus: function (e) { return e === d.activeElement && (!d.hasFocus || d.hasFocus()) && !!(e.type || e.href || ~e.tabIndex) }, enabled: de(!1), disabled: de(!0), checked: function (e) { var t = e.nodeName.toLowerCase(); return "input" === t && !!e.checked || "option" === t && !!e.selected }, selected: function (e) { return e.parentNode && e.parentNode.selectedIndex, !0 === e.selected }, empty: function (e) { for (e = e.firstChild; e; e = e.nextSibling)if (e.nodeType < 6) return !1; return !0 }, parent: function (e) { return !r.pseudos.empty(e) }, header: function (e) { return Y.test(e.nodeName) }, input: function (e) { return G.test(e.nodeName) }, button: function (e) { var t = e.nodeName.toLowerCase(); return "input" === t && "button" === e.type || "button" === t }, text: function (e) { var t; return "input" === e.nodeName.toLowerCase() && "text" === e.type && (null == (t = e.getAttribute("type")) || "text" === t.toLowerCase()) }, first: he(function () { return [0] }), last: he(function (e, t) { return [t - 1] }), eq: he(function (e, t, n) { return [n < 0 ? n + t : n] }), even: he(function (e, t) { for (var n = 0; n < t; n += 2)e.push(n); return e }), odd: he(function (e, t) { for (var n = 1; n < t; n += 2)e.push(n); return e }), lt: he(function (e, t, n) { for (var r = n < 0 ? n + t : n; --r >= 0;)e.push(r); return e }), gt: he(function (e, t, n) { for (var r = n < 0 ? n + t : n; ++r < t;)e.push(r); return e }) } }).pseudos.nth = r.pseudos.eq; for (t in { radio: !0, checkbox: !0, file: !0, password: !0, image: !0 }) r.pseudos[t] = fe(t); for (t in { submit: !0, reset: !0 }) r.pseudos[t] = pe(t); function ye() { } ye.prototype = r.filters = r.pseudos, r.setFilters = new ye, a = oe.tokenize = function (e, t) { var n, i, o, a, s, u, l, c = k[e + " "]; if (c) return t ? 0 : c.slice(0); s = e, u = [], l = r.preFilter; while (s) { n && !(i = F.exec(s)) || (i && (s = s.slice(i[0].length) || s), u.push(o = [])), n = !1, (i = _.exec(s)) && (n = i.shift(), o.push({ value: n, type: i[0].replace(B, " ") }), s = s.slice(n.length)); for (a in r.filter) !(i = V[a].exec(s)) || l[a] && !(i = l[a](i)) || (n = i.shift(), o.push({ value: n, type: a, matches: i }), s = s.slice(n.length)); if (!n) break } return t ? s.length : s ? oe.error(e) : k(e, u).slice(0) }; function ve(e) { for (var t = 0, n = e.length, r = ""; t < n; t++)r += e[t].value; return r } function me(e, t, n) { var r = t.dir, i = t.next, o = i || r, a = n && "parentNode" === o, s = C++; return t.first ? function (t, n, i) { while (t = t[r]) if (1 === t.nodeType || a) return e(t, n, i); return !1 } : function (t, n, u) { var l, c, f, p = [T, s]; if (u) { while (t = t[r]) if ((1 === t.nodeType || a) && e(t, n, u)) return !0 } else while (t = t[r]) if (1 === t.nodeType || a) if (f = t[b] || (t[b] = {}), c = f[t.uniqueID] || (f[t.uniqueID] = {}), i && i === t.nodeName.toLowerCase()) t = t[r] || t; else { if ((l = c[o]) && l[0] === T && l[1] === s) return p[2] = l[2]; if (c[o] = p, p[2] = e(t, n, u)) return !0 } return !1 } } function xe(e) { return e.length > 1 ? function (t, n, r) { var i = e.length; while (i--) if (!e[i](t, n, r)) return !1; return !0 } : e[0] } function be(e, t, n) { for (var r = 0, i = t.length; r < i; r++)oe(e, t[r], n); return n } function we(e, t, n, r, i) { for (var o, a = [], s = 0, u = e.length, l = null != t; s < u; s++)(o = e[s]) && (n && !n(o, r, i) || (a.push(o), l && t.push(s))); return a } function Te(e, t, n, r, i, o) { return r && !r[b] && (r = Te(r)), i && !i[b] && (i = Te(i, o)), se(function (o, a, s, u) { var l, c, f, p = [], d = [], h = a.length, g = o || be(t || "*", s.nodeType ? [s] : s, []), y = !e || !o && t ? g : we(g, p, e, s, u), v = n ? i || (o ? e : h || r) ? [] : a : y; if (n && n(y, v, s, u), r) { l = we(v, d), r(l, [], s, u), c = l.length; while (c--) (f = l[c]) && (v[d[c]] = !(y[d[c]] = f)) } if (o) { if (i || e) { if (i) { l = [], c = v.length; while (c--) (f = v[c]) && l.push(y[c] = f); i(null, v = [], l, u) } c = v.length; while (c--) (f = v[c]) && (l = i ? O(o, f) : p[c]) > -1 && (o[l] = !(a[l] = f)) } } else v = we(v === a ? v.splice(h, v.length) : v), i ? i(null, a, v, u) : L.apply(a, v) }) } function Ce(e) { for (var t, n, i, o = e.length, a = r.relative[e[0].type], s = a || r.relative[" "], u = a ? 1 : 0, c = me(function (e) { return e === t }, s, !0), f = me(function (e) { return O(t, e) > -1 }, s, !0), p = [function (e, n, r) { var i = !a && (r || n !== l) || ((t = n).nodeType ? c(e, n, r) : f(e, n, r)); return t = null, i }]; u < o; u++)if (n = r.relative[e[u].type]) p = [me(xe(p), n)]; else { if ((n = r.filter[e[u].type].apply(null, e[u].matches))[b]) { for (i = ++u; i < o; i++)if (r.relative[e[i].type]) break; return Te(u > 1 && xe(p), u > 1 && ve(e.slice(0, u - 1).concat({ value: " " === e[u - 2].type ? "*" : "" })).replace(B, "$1"), n, u < i && Ce(e.slice(u, i)), i < o && Ce(e = e.slice(i)), i < o && ve(e)) } p.push(n) } return xe(p) } function Ee(e, t) { var n = t.length > 0, i = e.length > 0, o = function (o, a, s, u, c) { var f, h, y, v = 0, m = "0", x = o && [], b = [], w = l, C = o || i && r.find.TAG("*", c), E = T += null == w ? 1 : Math.random() || .1, k = C.length; for (c && (l = a === d || a || c); m !== k && null != (f = C[m]); m++) { if (i && f) { h = 0, a || f.ownerDocument === d || (p(f), s = !g); while (y = e[h++]) if (y(f, a || d, s)) { u.push(f); break } c && (T = E) } n && ((f = !y && f) && v-- , o && x.push(f)) } if (v += m, n && m !== v) { h = 0; while (y = t[h++]) y(x, b, a, s); if (o) { if (v > 0) while (m--) x[m] || b[m] || (b[m] = j.call(u)); b = we(b) } L.apply(u, b), c && !o && b.length > 0 && v + t.length > 1 && oe.uniqueSort(u) } return c && (T = E, l = w), x }; return n ? se(o) : o } return s = oe.compile = function (e, t) { var n, r = [], i = [], o = S[e + " "]; if (!o) { t || (t = a(e)), n = t.length; while (n--) (o = Ce(t[n]))[b] ? r.push(o) : i.push(o); (o = S(e, Ee(i, r))).selector = e } return o }, u = oe.select = function (e, t, n, i) { var o, u, l, c, f, p = "function" == typeof e && e, d = !i && a(e = p.selector || e); if (n = n || [], 1 === d.length) { if ((u = d[0] = d[0].slice(0)).length > 2 && "ID" === (l = u[0]).type && 9 === t.nodeType && g && r.relative[u[1].type]) { if (!(t = (r.find.ID(l.matches[0].replace(Z, ee), t) || [])[0])) return n; p && (t = t.parentNode), e = e.slice(u.shift().value.length) } o = V.needsContext.test(e) ? 0 : u.length; while (o--) { if (l = u[o], r.relative[c = l.type]) break; if ((f = r.find[c]) && (i = f(l.matches[0].replace(Z, ee), K.test(u[0].type) && ge(t.parentNode) || t))) { if (u.splice(o, 1), !(e = i.length && ve(u))) return L.apply(n, i), n; break } } } return (p || s(e, d))(i, t, !g, n, !t || K.test(e) && ge(t.parentNode) || t), n }, n.sortStable = b.split("").sort(D).join("") === b, n.detectDuplicates = !!f, p(), n.sortDetached = ue(function (e) { return 1 & e.compareDocumentPosition(d.createElement("fieldset")) }), ue(function (e) { return e.innerHTML = " ", "#" === e.firstChild.getAttribute("href") }) || le("type|href|height|width", function (e, t, n) { if (!n) return e.getAttribute(t, "type" === t.toLowerCase() ? 1 : 2) }), n.attributes && ue(function (e) { return e.innerHTML = " ", e.firstChild.setAttribute("value", ""), "" === e.firstChild.getAttribute("value") }) || le("value", function (e, t, n) { if (!n && "input" === e.nodeName.toLowerCase()) return e.defaultValue }), ue(function (e) { return null == e.getAttribute("disabled") }) || le(P, function (e, t, n) { var r; if (!n) return !0 === e[t] ? t.toLowerCase() : (r = e.getAttributeNode(t)) && r.specified ? r.value : null }), oe }(e); w.find = E, w.expr = E.selectors, w.expr[":"] = w.expr.pseudos, w.uniqueSort = w.unique = E.uniqueSort, w.text = E.getText, w.isXMLDoc = E.isXML, w.contains = E.contains, w.escapeSelector = E.escape; var k = function (e, t, n) { var r = [], i = void 0 !== n; while ((e = e[t]) && 9 !== e.nodeType) if (1 === e.nodeType) { if (i && w(e).is(n)) break; r.push(e) } return r }, S = function (e, t) { for (var n = []; e; e = e.nextSibling)1 === e.nodeType && e !== t && n.push(e); return n }, D = w.expr.match.needsContext; function N(e, t) { return e.nodeName && e.nodeName.toLowerCase() === t.toLowerCase() } var A = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i; function j(e, t, n) { return g(t) ? w.grep(e, function (e, r) { return !!t.call(e, r, e) !== n }) : t.nodeType ? w.grep(e, function (e) { return e === t !== n }) : "string" != typeof t ? w.grep(e, function (e) { return u.call(t, e) > -1 !== n }) : w.filter(t, e, n) } w.filter = function (e, t, n) { var r = t[0]; return n && (e = ":not(" + e + ")"), 1 === t.length && 1 === r.nodeType ? w.find.matchesSelector(r, e) ? [r] : [] : w.find.matches(e, w.grep(t, function (e) { return 1 === e.nodeType })) }, w.fn.extend({ find: function (e) { var t, n, r = this.length, i = this; if ("string" != typeof e) return this.pushStack(w(e).filter(function () { for (t = 0; t < r; t++)if (w.contains(i[t], this)) return !0 })); for (n = this.pushStack([]), t = 0; t < r; t++)w.find(e, i[t], n); return r > 1 ? w.uniqueSort(n) : n }, filter: function (e) { return this.pushStack(j(this, e || [], !1)) }, not: function (e) { return this.pushStack(j(this, e || [], !0)) }, is: function (e) { return !!j(this, "string" == typeof e && D.test(e) ? w(e) : e || [], !1).length } }); var q, L = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/; (w.fn.init = function (e, t, n) { var i, o; if (!e) return this; if (n = n || q, "string" == typeof e) { if (!(i = "<" === e[0] && ">" === e[e.length - 1] && e.length >= 3 ? [null, e, null] : L.exec(e)) || !i[1] && t) return !t || t.jquery ? (t || n).find(e) : this.constructor(t).find(e); if (i[1]) { if (t = t instanceof w ? t[0] : t, w.merge(this, w.parseHTML(i[1], t && t.nodeType ? t.ownerDocument || t : r, !0)), A.test(i[1]) && w.isPlainObject(t)) for (i in t) g(this[i]) ? this[i](t[i]) : this.attr(i, t[i]); return this } return (o = r.getElementById(i[2])) && (this[0] = o, this.length = 1), this } return e.nodeType ? (this[0] = e, this.length = 1, this) : g(e) ? void 0 !== n.ready ? n.ready(e) : e(w) : w.makeArray(e, this) }).prototype = w.fn, q = w(r); var H = /^(?:parents|prev(?:Until|All))/, O = { children: !0, contents: !0, next: !0, prev: !0 }; w.fn.extend({ has: function (e) { var t = w(e, this), n = t.length; return this.filter(function () { for (var e = 0; e < n; e++)if (w.contains(this, t[e])) return !0 }) }, closest: function (e, t) { var n, r = 0, i = this.length, o = [], a = "string" != typeof e && w(e); if (!D.test(e)) for (; r < i; r++)for (n = this[r]; n && n !== t; n = n.parentNode)if (n.nodeType < 11 && (a ? a.index(n) > -1 : 1 === n.nodeType && w.find.matchesSelector(n, e))) { o.push(n); break } return this.pushStack(o.length > 1 ? w.uniqueSort(o) : o) }, index: function (e) { return e ? "string" == typeof e ? u.call(w(e), this[0]) : u.call(this, e.jquery ? e[0] : e) : this[0] && this[0].parentNode ? this.first().prevAll().length : -1 }, add: function (e, t) { return this.pushStack(w.uniqueSort(w.merge(this.get(), w(e, t)))) }, addBack: function (e) { return this.add(null == e ? this.prevObject : this.prevObject.filter(e)) } }); function P(e, t) { while ((e = e[t]) && 1 !== e.nodeType); return e } w.each({ parent: function (e) { var t = e.parentNode; return t && 11 !== t.nodeType ? t : null }, parents: function (e) { return k(e, "parentNode") }, parentsUntil: function (e, t, n) { return k(e, "parentNode", n) }, next: function (e) { return P(e, "nextSibling") }, prev: function (e) { return P(e, "previousSibling") }, nextAll: function (e) { return k(e, "nextSibling") }, prevAll: function (e) { return k(e, "previousSibling") }, nextUntil: function (e, t, n) { return k(e, "nextSibling", n) }, prevUntil: function (e, t, n) { return k(e, "previousSibling", n) }, siblings: function (e) { return S((e.parentNode || {}).firstChild, e) }, children: function (e) { return S(e.firstChild) }, contents: function (e) { return N(e, "iframe") ? e.contentDocument : (N(e, "template") && (e = e.content || e), w.merge([], e.childNodes)) } }, function (e, t) { w.fn[e] = function (n, r) { var i = w.map(this, t, n); return "Until" !== e.slice(-5) && (r = n), r && "string" == typeof r && (i = w.filter(r, i)), this.length > 1 && (O[e] || w.uniqueSort(i), H.test(e) && i.reverse()), this.pushStack(i) } }); var M = /[^\x20\t\r\n\f]+/g; function R(e) { var t = {}; return w.each(e.match(M) || [], function (e, n) { t[n] = !0 }), t } w.Callbacks = function (e) { e = "string" == typeof e ? R(e) : w.extend({}, e); var t, n, r, i, o = [], a = [], s = -1, u = function () { for (i = i || e.once, r = t = !0; a.length; s = -1) { n = a.shift(); while (++s < o.length) !1 === o[s].apply(n[0], n[1]) && e.stopOnFalse && (s = o.length, n = !1) } e.memory || (n = !1), t = !1, i && (o = n ? [] : "") }, l = { add: function () { return o && (n && !t && (s = o.length - 1, a.push(n)), function t(n) { w.each(n, function (n, r) { g(r) ? e.unique && l.has(r) || o.push(r) : r && r.length && "string" !== x(r) && t(r) }) }(arguments), n && !t && u()), this }, remove: function () { return w.each(arguments, function (e, t) { var n; while ((n = w.inArray(t, o, n)) > -1) o.splice(n, 1), n <= s && s-- }), this }, has: function (e) { return e ? w.inArray(e, o) > -1 : o.length > 0 }, empty: function () { return o && (o = []), this }, disable: function () { return i = a = [], o = n = "", this }, disabled: function () { return !o }, lock: function () { return i = a = [], n || t || (o = n = ""), this }, locked: function () { return !!i }, fireWith: function (e, n) { return i || (n = [e, (n = n || []).slice ? n.slice() : n], a.push(n), t || u()), this }, fire: function () { return l.fireWith(this, arguments), this }, fired: function () { return !!r } }; return l }; function I(e) { return e } function W(e) { throw e } function $(e, t, n, r) { var i; try { e && g(i = e.promise) ? i.call(e).done(t).fail(n) : e && g(i = e.then) ? i.call(e, t, n) : t.apply(void 0, [e].slice(r)) } catch (e) { n.apply(void 0, [e]) } } w.extend({ Deferred: function (t) { var n = [["notify", "progress", w.Callbacks("memory"), w.Callbacks("memory"), 2], ["resolve", "done", w.Callbacks("once memory"), w.Callbacks("once memory"), 0, "resolved"], ["reject", "fail", w.Callbacks("once memory"), w.Callbacks("once memory"), 1, "rejected"]], r = "pending", i = { state: function () { return r }, always: function () { return o.done(arguments).fail(arguments), this }, "catch": function (e) { return i.then(null, e) }, pipe: function () { var e = arguments; return w.Deferred(function (t) { w.each(n, function (n, r) { var i = g(e[r[4]]) && e[r[4]]; o[r[1]](function () { var e = i && i.apply(this, arguments); e && g(e.promise) ? e.promise().progress(t.notify).done(t.resolve).fail(t.reject) : t[r[0] + "With"](this, i ? [e] : arguments) }) }), e = null }).promise() }, then: function (t, r, i) { var o = 0; function a(t, n, r, i) { return function () { var s = this, u = arguments, l = function () { var e, l; if (!(t < o)) { if ((e = r.apply(s, u)) === n.promise()) throw new TypeError("Thenable self-resolution"); l = e && ("object" == typeof e || "function" == typeof e) && e.then, g(l) ? i ? l.call(e, a(o, n, I, i), a(o, n, W, i)) : (o++ , l.call(e, a(o, n, I, i), a(o, n, W, i), a(o, n, I, n.notifyWith))) : (r !== I && (s = void 0, u = [e]), (i || n.resolveWith)(s, u)) } }, c = i ? l : function () { try { l() } catch (e) { w.Deferred.exceptionHook && w.Deferred.exceptionHook(e, c.stackTrace), t + 1 >= o && (r !== W && (s = void 0, u = [e]), n.rejectWith(s, u)) } }; t ? c() : (w.Deferred.getStackHook && (c.stackTrace = w.Deferred.getStackHook()), e.setTimeout(c)) } } return w.Deferred(function (e) { n[0][3].add(a(0, e, g(i) ? i : I, e.notifyWith)), n[1][3].add(a(0, e, g(t) ? t : I)), n[2][3].add(a(0, e, g(r) ? r : W)) }).promise() }, promise: function (e) { return null != e ? w.extend(e, i) : i } }, o = {}; return w.each(n, function (e, t) { var a = t[2], s = t[5]; i[t[1]] = a.add, s && a.add(function () { r = s }, n[3 - e][2].disable, n[3 - e][3].disable, n[0][2].lock, n[0][3].lock), a.add(t[3].fire), o[t[0]] = function () { return o[t[0] + "With"](this === o ? void 0 : this, arguments), this }, o[t[0] + "With"] = a.fireWith }), i.promise(o), t && t.call(o, o), o }, when: function (e) { var t = arguments.length, n = t, r = Array(n), i = o.call(arguments), a = w.Deferred(), s = function (e) { return function (n) { r[e] = this, i[e] = arguments.length > 1 ? o.call(arguments) : n, --t || a.resolveWith(r, i) } }; if (t <= 1 && ($(e, a.done(s(n)).resolve, a.reject, !t), "pending" === a.state() || g(i[n] && i[n].then))) return a.then(); while (n--) $(i[n], s(n), a.reject); return a.promise() } }); var B = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; w.Deferred.exceptionHook = function (t, n) { e.console && e.console.warn && t && B.test(t.name) && e.console.warn("jQuery.Deferred exception: " + t.message, t.stack, n) }, w.readyException = function (t) { e.setTimeout(function () { throw t }) }; var F = w.Deferred(); w.fn.ready = function (e) { return F.then(e)["catch"](function (e) { w.readyException(e) }), this }, w.extend({ isReady: !1, readyWait: 1, ready: function (e) { (!0 === e ? --w.readyWait : w.isReady) || (w.isReady = !0, !0 !== e && --w.readyWait > 0 || F.resolveWith(r, [w])) } }), w.ready.then = F.then; function _() { r.removeEventListener("DOMContentLoaded", _), e.removeEventListener("load", _), w.ready() } "complete" === r.readyState || "loading" !== r.readyState && !r.documentElement.doScroll ? e.setTimeout(w.ready) : (r.addEventListener("DOMContentLoaded", _), e.addEventListener("load", _)); var z = function (e, t, n, r, i, o, a) { var s = 0, u = e.length, l = null == n; if ("object" === x(n)) { i = !0; for (s in n) z(e, t, s, n[s], !0, o, a) } else if (void 0 !== r && (i = !0, g(r) || (a = !0), l && (a ? (t.call(e, r), t = null) : (l = t, t = function (e, t, n) { return l.call(w(e), n) })), t)) for (; s < u; s++)t(e[s], n, a ? r : r.call(e[s], s, t(e[s], n))); return i ? e : l ? t.call(e) : u ? t(e[0], n) : o }, X = /^-ms-/, U = /-([a-z])/g; function V(e, t) { return t.toUpperCase() } function G(e) { return e.replace(X, "ms-").replace(U, V) } var Y = function (e) { return 1 === e.nodeType || 9 === e.nodeType || !+e.nodeType }; function Q() { this.expando = w.expando + Q.uid++ } Q.uid = 1, Q.prototype = { cache: function (e) { var t = e[this.expando]; return t || (t = {}, Y(e) && (e.nodeType ? e[this.expando] = t : Object.defineProperty(e, this.expando, { value: t, configurable: !0 }))), t }, set: function (e, t, n) { var r, i = this.cache(e); if ("string" == typeof t) i[G(t)] = n; else for (r in t) i[G(r)] = t[r]; return i }, get: function (e, t) { return void 0 === t ? this.cache(e) : e[this.expando] && e[this.expando][G(t)] }, access: function (e, t, n) { return void 0 === t || t && "string" == typeof t && void 0 === n ? this.get(e, t) : (this.set(e, t, n), void 0 !== n ? n : t) }, remove: function (e, t) { var n, r = e[this.expando]; if (void 0 !== r) { if (void 0 !== t) { n = (t = Array.isArray(t) ? t.map(G) : (t = G(t)) in r ? [t] : t.match(M) || []).length; while (n--) delete r[t[n]] } (void 0 === t || w.isEmptyObject(r)) && (e.nodeType ? e[this.expando] = void 0 : delete e[this.expando]) } }, hasData: function (e) { var t = e[this.expando]; return void 0 !== t && !w.isEmptyObject(t) } }; var J = new Q, K = new Q, Z = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, ee = /[A-Z]/g; function te(e) { return "true" === e || "false" !== e && ("null" === e ? null : e === +e + "" ? +e : Z.test(e) ? JSON.parse(e) : e) } function ne(e, t, n) { var r; if (void 0 === n && 1 === e.nodeType) if (r = "data-" + t.replace(ee, "-$&").toLowerCase(), "string" == typeof (n = e.getAttribute(r))) { try { n = te(n) } catch (e) { } K.set(e, t, n) } else n = void 0; return n } w.extend({ hasData: function (e) { return K.hasData(e) || J.hasData(e) }, data: function (e, t, n) { return K.access(e, t, n) }, removeData: function (e, t) { K.remove(e, t) }, _data: function (e, t, n) { return J.access(e, t, n) }, _removeData: function (e, t) { J.remove(e, t) } }), w.fn.extend({ data: function (e, t) { var n, r, i, o = this[0], a = o && o.attributes; if (void 0 === e) { if (this.length && (i = K.get(o), 1 === o.nodeType && !J.get(o, "hasDataAttrs"))) { n = a.length; while (n--) a[n] && 0 === (r = a[n].name).indexOf("data-") && (r = G(r.slice(5)), ne(o, r, i[r])); J.set(o, "hasDataAttrs", !0) } return i } return "object" == typeof e ? this.each(function () { K.set(this, e) }) : z(this, function (t) { var n; if (o && void 0 === t) { if (void 0 !== (n = K.get(o, e))) return n; if (void 0 !== (n = ne(o, e))) return n } else this.each(function () { K.set(this, e, t) }) }, null, t, arguments.length > 1, null, !0) }, removeData: function (e) { return this.each(function () { K.remove(this, e) }) } }), w.extend({ queue: function (e, t, n) { var r; if (e) return t = (t || "fx") + "queue", r = J.get(e, t), n && (!r || Array.isArray(n) ? r = J.access(e, t, w.makeArray(n)) : r.push(n)), r || [] }, dequeue: function (e, t) { t = t || "fx"; var n = w.queue(e, t), r = n.length, i = n.shift(), o = w._queueHooks(e, t), a = function () { w.dequeue(e, t) }; "inprogress" === i && (i = n.shift(), r--), i && ("fx" === t && n.unshift("inprogress"), delete o.stop, i.call(e, a, o)), !r && o && o.empty.fire() }, _queueHooks: function (e, t) { var n = t + "queueHooks"; return J.get(e, n) || J.access(e, n, { empty: w.Callbacks("once memory").add(function () { J.remove(e, [t + "queue", n]) }) }) } }), w.fn.extend({ queue: function (e, t) { var n = 2; return "string" != typeof e && (t = e, e = "fx", n--), arguments.length < n ? w.queue(this[0], e) : void 0 === t ? this : this.each(function () { var n = w.queue(this, e, t); w._queueHooks(this, e), "fx" === e && "inprogress" !== n[0] && w.dequeue(this, e) }) }, dequeue: function (e) { return this.each(function () { w.dequeue(this, e) }) }, clearQueue: function (e) { return this.queue(e || "fx", []) }, promise: function (e, t) { var n, r = 1, i = w.Deferred(), o = this, a = this.length, s = function () { --r || i.resolveWith(o, [o]) }; "string" != typeof e && (t = e, e = void 0), e = e || "fx"; while (a--) (n = J.get(o[a], e + "queueHooks")) && n.empty && (r++ , n.empty.add(s)); return s(), i.promise(t) } }); var re = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, ie = new RegExp("^(?:([+-])=|)(" + re + ")([a-z%]*)$", "i"), oe = ["Top", "Right", "Bottom", "Left"], ae = function (e, t) { return "none" === (e = t || e).style.display || "" === e.style.display && w.contains(e.ownerDocument, e) && "none" === w.css(e, "display") }, se = function (e, t, n, r) { var i, o, a = {}; for (o in t) a[o] = e.style[o], e.style[o] = t[o]; i = n.apply(e, r || []); for (o in t) e.style[o] = a[o]; return i }; function ue(e, t, n, r) { var i, o, a = 20, s = r ? function () { return r.cur() } : function () { return w.css(e, t, "") }, u = s(), l = n && n[3] || (w.cssNumber[t] ? "" : "px"), c = (w.cssNumber[t] || "px" !== l && +u) && ie.exec(w.css(e, t)); if (c && c[3] !== l) { u /= 2, l = l || c[3], c = +u || 1; while (a--) w.style(e, t, c + l), (1 - o) * (1 - (o = s() / u || .5)) <= 0 && (a = 0), c /= o; c *= 2, w.style(e, t, c + l), n = n || [] } return n && (c = +c || +u || 0, i = n[1] ? c + (n[1] + 1) * n[2] : +n[2], r && (r.unit = l, r.start = c, r.end = i)), i } var le = {}; function ce(e) { var t, n = e.ownerDocument, r = e.nodeName, i = le[r]; return i || (t = n.body.appendChild(n.createElement(r)), i = w.css(t, "display"), t.parentNode.removeChild(t), "none" === i && (i = "block"), le[r] = i, i) } function fe(e, t) { for (var n, r, i = [], o = 0, a = e.length; o < a; o++)(r = e[o]).style && (n = r.style.display, t ? ("none" === n && (i[o] = J.get(r, "display") || null, i[o] || (r.style.display = "")), "" === r.style.display && ae(r) && (i[o] = ce(r))) : "none" !== n && (i[o] = "none", J.set(r, "display", n))); for (o = 0; o < a; o++)null != i[o] && (e[o].style.display = i[o]); return e } w.fn.extend({ show: function () { return fe(this, !0) }, hide: function () { return fe(this) }, toggle: function (e) { return "boolean" == typeof e ? e ? this.show() : this.hide() : this.each(function () { ae(this) ? w(this).show() : w(this).hide() }) } }); var pe = /^(?:checkbox|radio)$/i, de = /<([a-z][^\/\0>\x20\t\r\n\f]+)/i, he = /^$|^module$|\/(?:java|ecma)script/i, ge = { option: [1, "", " "], thead: [1, ""], col: [2, ""], tr: [2, ""], td: [3, ""], _default: [0, "", ""] }; ge.optgroup = ge.option, ge.tbody = ge.tfoot = ge.colgroup = ge.caption = ge.thead, ge.th = ge.td; function ye(e, t) { var n; return n = "undefined" != typeof e.getElementsByTagName ? e.getElementsByTagName(t || "*") : "undefined" != typeof e.querySelectorAll ? e.querySelectorAll(t || "*") : [], void 0 === t || t && N(e, t) ? w.merge([e], n) : n } function ve(e, t) { for (var n = 0, r = e.length; n < r; n++)J.set(e[n], "globalEval", !t || J.get(t[n], "globalEval")) } var me = /<|?\w+;/; function xe(e, t, n, r, i) { for (var o, a, s, u, l, c, f = t.createDocumentFragment(), p = [], d = 0, h = e.length; d < h; d++)if ((o = e[d]) || 0 === o) if ("object" === x(o)) w.merge(p, o.nodeType ? [o] : o); else if (me.test(o)) { a = a || f.appendChild(t.createElement("div")), s = (de.exec(o) || ["", ""])[1].toLowerCase(), u = ge[s] || ge._default, a.innerHTML = u[1] + w.htmlPrefilter(o) + u[2], c = u[0]; while (c--) a = a.lastChild; w.merge(p, a.childNodes), (a = f.firstChild).textContent = "" } else p.push(t.createTextNode(o)); f.textContent = "", d = 0; while (o = p[d++]) if (r && w.inArray(o, r) > -1) i && i.push(o); else if (l = w.contains(o.ownerDocument, o), a = ye(f.appendChild(o), "script"), l && ve(a), n) { c = 0; while (o = a[c++]) he.test(o.type || "") && n.push(o) } return f } !function () { var e = r.createDocumentFragment().appendChild(r.createElement("div")), t = r.createElement("input"); t.setAttribute("type", "radio"), t.setAttribute("checked", "checked"), t.setAttribute("name", "t"), e.appendChild(t), h.checkClone = e.cloneNode(!0).cloneNode(!0).lastChild.checked, e.innerHTML = "", h.noCloneChecked = !!e.cloneNode(!0).lastChild.defaultValue }(); var be = r.documentElement, we = /^key/, Te = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, Ce = /^([^.]*)(?:\.(.+)|)/; function Ee() { return !0 } function ke() { return !1 } function Se() { try { return r.activeElement } catch (e) { } } function De(e, t, n, r, i, o) { var a, s; if ("object" == typeof t) { "string" != typeof n && (r = r || n, n = void 0); for (s in t) De(e, s, n, r, t[s], o); return e } if (null == r && null == i ? (i = n, r = n = void 0) : null == i && ("string" == typeof n ? (i = r, r = void 0) : (i = r, r = n, n = void 0)), !1 === i) i = ke; else if (!i) return e; return 1 === o && (a = i, (i = function (e) { return w().off(e), a.apply(this, arguments) }).guid = a.guid || (a.guid = w.guid++)), e.each(function () { w.event.add(this, t, i, r, n) }) } w.event = { global: {}, add: function (e, t, n, r, i) { var o, a, s, u, l, c, f, p, d, h, g, y = J.get(e); if (y) { n.handler && (n = (o = n).handler, i = o.selector), i && w.find.matchesSelector(be, i), n.guid || (n.guid = w.guid++), (u = y.events) || (u = y.events = {}), (a = y.handle) || (a = y.handle = function (t) { return "undefined" != typeof w && w.event.triggered !== t.type ? w.event.dispatch.apply(e, arguments) : void 0 }), l = (t = (t || "").match(M) || [""]).length; while (l--) d = g = (s = Ce.exec(t[l]) || [])[1], h = (s[2] || "").split(".").sort(), d && (f = w.event.special[d] || {}, d = (i ? f.delegateType : f.bindType) || d, f = w.event.special[d] || {}, c = w.extend({ type: d, origType: g, data: r, handler: n, guid: n.guid, selector: i, needsContext: i && w.expr.match.needsContext.test(i), namespace: h.join(".") }, o), (p = u[d]) || ((p = u[d] = []).delegateCount = 0, f.setup && !1 !== f.setup.call(e, r, h, a) || e.addEventListener && e.addEventListener(d, a)), f.add && (f.add.call(e, c), c.handler.guid || (c.handler.guid = n.guid)), i ? p.splice(p.delegateCount++, 0, c) : p.push(c), w.event.global[d] = !0) } }, remove: function (e, t, n, r, i) { var o, a, s, u, l, c, f, p, d, h, g, y = J.hasData(e) && J.get(e); if (y && (u = y.events)) { l = (t = (t || "").match(M) || [""]).length; while (l--) if (s = Ce.exec(t[l]) || [], d = g = s[1], h = (s[2] || "").split(".").sort(), d) { f = w.event.special[d] || {}, p = u[d = (r ? f.delegateType : f.bindType) || d] || [], s = s[2] && new RegExp("(^|\\.)" + h.join("\\.(?:.*\\.|)") + "(\\.|$)"), a = o = p.length; while (o--) c = p[o], !i && g !== c.origType || n && n.guid !== c.guid || s && !s.test(c.namespace) || r && r !== c.selector && ("**" !== r || !c.selector) || (p.splice(o, 1), c.selector && p.delegateCount-- , f.remove && f.remove.call(e, c)); a && !p.length && (f.teardown && !1 !== f.teardown.call(e, h, y.handle) || w.removeEvent(e, d, y.handle), delete u[d]) } else for (d in u) w.event.remove(e, d + t[l], n, r, !0); w.isEmptyObject(u) && J.remove(e, "handle events") } }, dispatch: function (e) { var t = w.event.fix(e), n, r, i, o, a, s, u = new Array(arguments.length), l = (J.get(this, "events") || {})[t.type] || [], c = w.event.special[t.type] || {}; for (u[0] = t, n = 1; n < arguments.length; n++)u[n] = arguments[n]; if (t.delegateTarget = this, !c.preDispatch || !1 !== c.preDispatch.call(this, t)) { s = w.event.handlers.call(this, t, l), n = 0; while ((o = s[n++]) && !t.isPropagationStopped()) { t.currentTarget = o.elem, r = 0; while ((a = o.handlers[r++]) && !t.isImmediatePropagationStopped()) t.rnamespace && !t.rnamespace.test(a.namespace) || (t.handleObj = a, t.data = a.data, void 0 !== (i = ((w.event.special[a.origType] || {}).handle || a.handler).apply(o.elem, u)) && !1 === (t.result = i) && (t.preventDefault(), t.stopPropagation())) } return c.postDispatch && c.postDispatch.call(this, t), t.result } }, handlers: function (e, t) { var n, r, i, o, a, s = [], u = t.delegateCount, l = e.target; if (u && l.nodeType && !("click" === e.type && e.button >= 1)) for (; l !== this; l = l.parentNode || this)if (1 === l.nodeType && ("click" !== e.type || !0 !== l.disabled)) { for (o = [], a = {}, n = 0; n < u; n++)void 0 === a[i = (r = t[n]).selector + " "] && (a[i] = r.needsContext ? w(i, this).index(l) > -1 : w.find(i, this, null, [l]).length), a[i] && o.push(r); o.length && s.push({ elem: l, handlers: o }) } return l = this, u < t.length && s.push({ elem: l, handlers: t.slice(u) }), s }, addProp: function (e, t) { Object.defineProperty(w.Event.prototype, e, { enumerable: !0, configurable: !0, get: g(t) ? function () { if (this.originalEvent) return t(this.originalEvent) } : function () { if (this.originalEvent) return this.originalEvent[e] }, set: function (t) { Object.defineProperty(this, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) } }) }, fix: function (e) { return e[w.expando] ? e : new w.Event(e) }, special: { load: { noBubble: !0 }, focus: { trigger: function () { if (this !== Se() && this.focus) return this.focus(), !1 }, delegateType: "focusin" }, blur: { trigger: function () { if (this === Se() && this.blur) return this.blur(), !1 }, delegateType: "focusout" }, click: { trigger: function () { if ("checkbox" === this.type && this.click && N(this, "input")) return this.click(), !1 }, _default: function (e) { return N(e.target, "a") } }, beforeunload: { postDispatch: function (e) { void 0 !== e.result && e.originalEvent && (e.originalEvent.returnValue = e.result) } } } }, w.removeEvent = function (e, t, n) { e.removeEventListener && e.removeEventListener(t, n) }, w.Event = function (e, t) { if (!(this instanceof w.Event)) return new w.Event(e, t); e && e.type ? (this.originalEvent = e, this.type = e.type, this.isDefaultPrevented = e.defaultPrevented || void 0 === e.defaultPrevented && !1 === e.returnValue ? Ee : ke, this.target = e.target && 3 === e.target.nodeType ? e.target.parentNode : e.target, this.currentTarget = e.currentTarget, this.relatedTarget = e.relatedTarget) : this.type = e, t && w.extend(this, t), this.timeStamp = e && e.timeStamp || Date.now(), this[w.expando] = !0 }, w.Event.prototype = { constructor: w.Event, isDefaultPrevented: ke, isPropagationStopped: ke, isImmediatePropagationStopped: ke, isSimulated: !1, preventDefault: function () { var e = this.originalEvent; this.isDefaultPrevented = Ee, e && !this.isSimulated && e.preventDefault() }, stopPropagation: function () { var e = this.originalEvent; this.isPropagationStopped = Ee, e && !this.isSimulated && e.stopPropagation() }, stopImmediatePropagation: function () { var e = this.originalEvent; this.isImmediatePropagationStopped = Ee, e && !this.isSimulated && e.stopImmediatePropagation(), this.stopPropagation() } }, w.each({ altKey: !0, bubbles: !0, cancelable: !0, changedTouches: !0, ctrlKey: !0, detail: !0, eventPhase: !0, metaKey: !0, pageX: !0, pageY: !0, shiftKey: !0, view: !0, "char": !0, charCode: !0, key: !0, keyCode: !0, button: !0, buttons: !0, clientX: !0, clientY: !0, offsetX: !0, offsetY: !0, pointerId: !0, pointerType: !0, screenX: !0, screenY: !0, targetTouches: !0, toElement: !0, touches: !0, which: function (e) { var t = e.button; return null == e.which && we.test(e.type) ? null != e.charCode ? e.charCode : e.keyCode : !e.which && void 0 !== t && Te.test(e.type) ? 1 & t ? 1 : 2 & t ? 3 : 4 & t ? 2 : 0 : e.which } }, w.event.addProp), w.each({ mouseenter: "mouseover", mouseleave: "mouseout", pointerenter: "pointerover", pointerleave: "pointerout" }, function (e, t) { w.event.special[e] = { delegateType: t, bindType: t, handle: function (e) { var n, r = this, i = e.relatedTarget, o = e.handleObj; return i && (i === r || w.contains(r, i)) || (e.type = o.origType, n = o.handler.apply(this, arguments), e.type = t), n } } }), w.fn.extend({ on: function (e, t, n, r) { return De(this, e, t, n, r) }, one: function (e, t, n, r) { return De(this, e, t, n, r, 1) }, off: function (e, t, n) { var r, i; if (e && e.preventDefault && e.handleObj) return r = e.handleObj, w(e.delegateTarget).off(r.namespace ? r.origType + "." + r.namespace : r.origType, r.selector, r.handler), this; if ("object" == typeof e) { for (i in e) this.off(i, t, e[i]); return this } return !1 !== t && "function" != typeof t || (n = t, t = void 0), !1 === n && (n = ke), this.each(function () { w.event.remove(this, e, n, t) }) } }); var Ne = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, Ae = /
+ {# popper.js (for bootstrap) #}
+
+ {# Bootstrap JS #}
+
+ {# Bootstrap #}
+
+
+
+
+
+ {# stylesheet for body blocks#}
+
+
+ {# More stylesheets as needed #}
+ {% block styles %}{% endblock %}
+ {% block title %}FLOM Login{% endblock %}
+
+
+
+ {% block body %}
+ {# #}
+
+ {# #}
+
+
+
About FLOM
+
+ {% endblock %}
+
+