Compare commits
15 Commits
5c24228c20
...
crud-updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
709596eea2 | ||
|
|
8de2b7f29e | ||
|
|
5b0d04b702 | ||
|
|
cafe0b58d0 | ||
|
|
a1711afecc | ||
|
|
86f778b7ac | ||
|
|
574dcbb119 | ||
|
|
f9d625e905 | ||
|
|
214bfe20ac | ||
|
|
00a29b9db7 | ||
|
|
6430dc6904 | ||
|
|
c650dbce01 | ||
|
|
e3a42f4ba3 | ||
|
|
b7b5fb545b | ||
|
|
4005328979 |
9
.env.example
Normal file
9
.env.example
Normal file
@@ -0,0 +1,9 @@
|
||||
# JWT Configuration
|
||||
JWT_SECRET_KEY=your-secret-key-here
|
||||
JWT_TOKEN_EXPIRY=3600 # 1 hour in seconds
|
||||
|
||||
# Database Configuration
|
||||
DB_HOST=localhost
|
||||
DB_NAME=your_database_name
|
||||
DB_USER=your_database_user
|
||||
DB_PASS=your_database_password
|
||||
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# IDE files
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
1
.idea/Ecobuddy.iml
generated
1
.idea/Ecobuddy.iml
generated
@@ -4,5 +4,6 @@
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="leaflet" level="application" />
|
||||
</component>
|
||||
</module>
|
||||
24
.idea/dataSources.xml
generated
24
.idea/dataSources.xml
generated
@@ -1,11 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="ecobuddy" uuid="b932ada6-ed77-47fa-96d8-d6dfa86a6ca2">
|
||||
<data-source source="LOCAL" name="ecobuddynew.sqlite" uuid="6566010b-b220-4baf-bb3e-99178c3287f0">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/Databases/ecobuddy.sqlite</jdbc-url>
|
||||
<jdbc-url>jdbc:sqlite:Databases/ecobuddynew.sqlite</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="ecobuddynew" uuid="b5d0338c-4f7c-4008-ba23-032fa68749c1">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/Databases/ecobuddynew.sqlite</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
<libraries>
|
||||
<library>
|
||||
@@ -14,7 +21,20 @@
|
||||
<library>
|
||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
|
||||
</library>
|
||||
<library>
|
||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
|
||||
</library>
|
||||
<library>
|
||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
|
||||
</library>
|
||||
</libraries>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="ecobuddy.sqlite" uuid="5216c958-85d2-48a7-b57e-256771f5c73c">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:Databases/ecobuddy.sqlite</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/jsLibraryMappings.xml
generated
2
.idea/jsLibraryMappings.xml
generated
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<file url="PROJECT" libraries="{jquery}" />
|
||||
<file url="PROJECT" libraries="{leaflet}" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/php.xml
generated
2
.idea/php.xml
generated
@@ -10,7 +10,7 @@
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.1" />
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
|
||||
0
.idea/sqldialects.xml
generated
Normal file → Executable file
0
.idea/sqldialects.xml
generated
Normal file → Executable file
@@ -1 +0,0 @@
|
||||
,boris,boris-ThinkPad-T480,07.11.2024 12:14,file:///home/boris/.config/libreoffice/4;
|
||||
@@ -1 +0,0 @@
|
||||
,boris,boris-ThinkPad-T480,08.11.2024 12:14,file:///home/boris/.config/libreoffice/4;
|
||||
Binary file not shown.
232
Databases/add_facilities.py
Normal file
232
Databases/add_facilities.py
Normal file
@@ -0,0 +1,232 @@
|
||||
import sqlite3
|
||||
import random
|
||||
|
||||
# Connect to the SQLite database
|
||||
conn = sqlite3.connect('Databases/ecobuddy.sqlite')
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Check if we need to add any new categories
|
||||
cursor.execute("SELECT id FROM ecoCategories")
|
||||
existing_categories = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# Add two new categories
|
||||
new_categories = [
|
||||
(16, "Urban Farms"),
|
||||
(17, "Rainwater Harvesting Systems")
|
||||
]
|
||||
|
||||
for category in new_categories:
|
||||
if category[0] not in existing_categories:
|
||||
cursor.execute("INSERT INTO ecoCategories (id, name) VALUES (?, ?)", category)
|
||||
print(f"Added new category: {category[1]}")
|
||||
|
||||
# Get list of user IDs for contributors
|
||||
cursor.execute("SELECT id FROM ecoUser")
|
||||
user_ids = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# Define 10 new ecological facilities in the UK with accurate location data
|
||||
new_facilities = [
|
||||
{
|
||||
"title": "Community Garden Hackney",
|
||||
"category": 12, # Pollinator Gardens
|
||||
"description": "Urban garden with native plants to support local pollinators",
|
||||
"houseNumber": "45",
|
||||
"streetName": "Dalston Lane",
|
||||
"county": "Greater London",
|
||||
"town": "London",
|
||||
"postcode": "E8 3AH",
|
||||
"lng": -0.0612,
|
||||
"lat": 51.5476,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Recently expanded with new wildflower section",
|
||||
"Volunteer days every Saturday"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Rooftop Solar Farm",
|
||||
"category": 8, # Green Roofs
|
||||
"description": "Combined green roof and solar panel installation on commercial building",
|
||||
"houseNumber": "120",
|
||||
"streetName": "Deansgate",
|
||||
"county": "Greater Manchester",
|
||||
"town": "Manchester",
|
||||
"postcode": "M3 2QJ",
|
||||
"lng": -2.2484,
|
||||
"lat": 53.4808,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Generates power for the entire building"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Edinburgh Tool Library",
|
||||
"category": 15, # Community Tool Libraries
|
||||
"description": "Borrow tools instead of buying them - reducing waste and consumption",
|
||||
"houseNumber": "25",
|
||||
"streetName": "Leith Walk",
|
||||
"county": "Edinburgh",
|
||||
"town": "Edinburgh",
|
||||
"postcode": "EH6 8LN",
|
||||
"lng": -3.1752,
|
||||
"lat": 55.9677,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": []
|
||||
},
|
||||
{
|
||||
"title": "Cardiff Bay Water Refill Station",
|
||||
"category": 9, # Public Water Refill Stations
|
||||
"description": "Free water refill station to reduce plastic bottle usage",
|
||||
"houseNumber": "3",
|
||||
"streetName": "Mermaid Quay",
|
||||
"county": "Cardiff",
|
||||
"town": "Cardiff",
|
||||
"postcode": "CF10 5BZ",
|
||||
"lng": -3.1644,
|
||||
"lat": 51.4644,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Recently cleaned and maintained",
|
||||
"High usage during summer months"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Bristol Urban Farm",
|
||||
"category": 16, # Urban Farms (new category)
|
||||
"description": "Community-run urban farm providing local produce and education",
|
||||
"houseNumber": "18",
|
||||
"streetName": "Stapleton Road",
|
||||
"county": "Bristol",
|
||||
"town": "Bristol",
|
||||
"postcode": "BS5 0RA",
|
||||
"lng": -2.5677,
|
||||
"lat": 51.4635,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Open for volunteers Tuesday-Sunday"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Newcastle Rainwater Collection System",
|
||||
"category": 17, # Rainwater Harvesting Systems (new category)
|
||||
"description": "Public demonstration of rainwater harvesting for garden irrigation",
|
||||
"houseNumber": "55",
|
||||
"streetName": "Northumberland Street",
|
||||
"county": "Tyne and Wear",
|
||||
"town": "Newcastle upon Tyne",
|
||||
"postcode": "NE1 7DH",
|
||||
"lng": -1.6178,
|
||||
"lat": 54.9783,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": []
|
||||
},
|
||||
{
|
||||
"title": "Brighton Beach Solar Bench",
|
||||
"category": 7, # Solar-Powered Benches
|
||||
"description": "Solar-powered bench with USB charging ports and WiFi",
|
||||
"houseNumber": "",
|
||||
"streetName": "Kings Road",
|
||||
"county": "East Sussex",
|
||||
"town": "Brighton",
|
||||
"postcode": "BN1 2FN",
|
||||
"lng": -0.1426,
|
||||
"lat": 50.8214,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Popular spot for tourists",
|
||||
"One USB port currently not working"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Leeds Community Compost Hub",
|
||||
"category": 6, # Community Compost Bins
|
||||
"description": "Large-scale community composting facility for local residents",
|
||||
"houseNumber": "78",
|
||||
"streetName": "Woodhouse Lane",
|
||||
"county": "West Yorkshire",
|
||||
"town": "Leeds",
|
||||
"postcode": "LS2 9JT",
|
||||
"lng": -1.5491,
|
||||
"lat": 53.8067,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Recently expanded capacity"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Glasgow EV Charging Hub",
|
||||
"category": 4, # Public EV Charging Stations
|
||||
"description": "Multi-vehicle EV charging station with fast chargers",
|
||||
"houseNumber": "42",
|
||||
"streetName": "Buchanan Street",
|
||||
"county": "Glasgow",
|
||||
"town": "Glasgow",
|
||||
"postcode": "G1 3JX",
|
||||
"lng": -4.2526,
|
||||
"lat": 55.8621,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"6 charging points available",
|
||||
"24/7 access"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Oxford E-Waste Collection Center",
|
||||
"category": 13, # E-Waste Collection Bins
|
||||
"description": "Dedicated facility for proper disposal and recycling of electronic waste",
|
||||
"houseNumber": "15",
|
||||
"streetName": "St Aldate's",
|
||||
"county": "Oxfordshire",
|
||||
"town": "Oxford",
|
||||
"postcode": "OX1 1BX",
|
||||
"lng": -1.2577,
|
||||
"lat": 51.7520,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": []
|
||||
}
|
||||
]
|
||||
|
||||
# Insert facilities into the database
|
||||
for facility in new_facilities:
|
||||
cursor.execute("""
|
||||
INSERT INTO ecoFacilities
|
||||
(title, category, description, houseNumber, streetName, county, town, postcode, lng, lat, contributor)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
facility["title"],
|
||||
facility["category"],
|
||||
facility["description"],
|
||||
facility["houseNumber"],
|
||||
facility["streetName"],
|
||||
facility["county"],
|
||||
facility["town"],
|
||||
facility["postcode"],
|
||||
facility["lng"],
|
||||
facility["lat"],
|
||||
facility["contributor"]
|
||||
))
|
||||
|
||||
# Get the ID of the inserted facility
|
||||
facility_id = cursor.lastrowid
|
||||
|
||||
# Add status comments if any
|
||||
for comment in facility["status_comments"]:
|
||||
cursor.execute("""
|
||||
INSERT INTO ecoFacilityStatus (facilityId, statusComment)
|
||||
VALUES (?, ?)
|
||||
""", (facility_id, comment))
|
||||
|
||||
print(f"Added facility: {facility['title']} in {facility['town']}")
|
||||
|
||||
# Commit the changes and close the connection
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print("\nSuccessfully added 10 new ecological facilities to the database.")
|
||||
|
||||
Using the test data in the ecoCategories, ecoFacilities, and ecoFacilityStatus, please create 10 new ecological facilities with the following constraints:
|
||||
Must be located in the United Kingdom (Names of areas, towns, cities, counties)
|
||||
Postcode, Latitude and Longitude must be fairly accurate to the location you have generated for the area.
|
||||
More categories may be made, it is up to you, but make sure foreign keys are respected.
|
||||
Contributor may be of any user in the database.
|
||||
Not all facilities must have statusComments, however facilities may have multiple statusComments.
|
||||
BIN
Databases/ecobuddy.sqlite
Executable file → Normal file
BIN
Databases/ecobuddy.sqlite
Executable file → Normal file
Binary file not shown.
BIN
Databases/ecobuddynew.sqlite
Executable file
BIN
Databases/ecobuddynew.sqlite
Executable file
Binary file not shown.
66
Databases/facility_generation_log.txt
Normal file
66
Databases/facility_generation_log.txt
Normal file
@@ -0,0 +1,66 @@
|
||||
Starting facility generation at 2025-03-14 22:20:38.302675
|
||||
Target: 1000 new facilities
|
||||
|
||||
Generating facilities...
|
||||
Generated 100 facilities so far...
|
||||
Generated 200 facilities so far...
|
||||
Generated 300 facilities so far...
|
||||
Generated 400 facilities so far...
|
||||
Generated 500 facilities so far...
|
||||
Generated 600 facilities so far...
|
||||
Generated 700 facilities so far...
|
||||
Generated 800 facilities so far...
|
||||
Generated 900 facilities so far...
|
||||
Generated 1000 facilities so far...
|
||||
|
||||
Inserting facilities into database...
|
||||
Inserted batch 1/20
|
||||
Inserted batch 2/20
|
||||
Inserted batch 3/20
|
||||
Inserted batch 4/20
|
||||
Inserted batch 5/20
|
||||
Inserted batch 6/20
|
||||
Inserted batch 7/20
|
||||
Inserted batch 8/20
|
||||
Inserted batch 9/20
|
||||
Inserted batch 10/20
|
||||
Inserted batch 11/20
|
||||
Inserted batch 12/20
|
||||
Inserted batch 13/20
|
||||
Inserted batch 14/20
|
||||
Inserted batch 15/20
|
||||
Inserted batch 16/20
|
||||
Inserted batch 17/20
|
||||
Inserted batch 18/20
|
||||
Inserted batch 19/20
|
||||
Inserted batch 20/20
|
||||
|
||||
Inserting status comments...
|
||||
Inserted comment batch 1/23
|
||||
Inserted comment batch 2/23
|
||||
Inserted comment batch 3/23
|
||||
Inserted comment batch 4/23
|
||||
Inserted comment batch 5/23
|
||||
Inserted comment batch 6/23
|
||||
Inserted comment batch 7/23
|
||||
Inserted comment batch 8/23
|
||||
Inserted comment batch 9/23
|
||||
Inserted comment batch 10/23
|
||||
Inserted comment batch 11/23
|
||||
Inserted comment batch 12/23
|
||||
Inserted comment batch 13/23
|
||||
Inserted comment batch 14/23
|
||||
Inserted comment batch 15/23
|
||||
Inserted comment batch 16/23
|
||||
Inserted comment batch 17/23
|
||||
Inserted comment batch 18/23
|
||||
Inserted comment batch 19/23
|
||||
Inserted comment batch 20/23
|
||||
Inserted comment batch 21/23
|
||||
Inserted comment batch 22/23
|
||||
Inserted comment batch 23/23
|
||||
|
||||
Generation complete at 2025-03-14 22:20:38.336715
|
||||
Total facilities in database: 1030
|
||||
Total status comments in database: 1147
|
||||
Generated facilities saved to generated_facilities.csv for reference
|
||||
568
Databases/generate_bulk_facilities.py
Normal file
568
Databases/generate_bulk_facilities.py
Normal file
@@ -0,0 +1,568 @@
|
||||
import sqlite3
|
||||
import random
|
||||
import csv
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
# Connect to the SQLite database
|
||||
conn = sqlite3.connect('Databases/ecobuddy.sqlite')
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Get current max facility ID
|
||||
cursor.execute("SELECT MAX(id) FROM ecoFacilities")
|
||||
max_facility_id = cursor.fetchone()[0] or 0
|
||||
|
||||
# Get list of user IDs for contributors
|
||||
cursor.execute("SELECT id FROM ecoUser")
|
||||
user_ids = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# Get list of categories
|
||||
cursor.execute("SELECT id, name FROM ecoCategories")
|
||||
categories = {row[0]: row[1] for row in cursor.fetchall()}
|
||||
|
||||
# UK Cities and Towns with their counties and approximate coordinates
|
||||
uk_locations = [
|
||||
# Format: Town/City, County, Latitude, Longitude, Postcode Area
|
||||
("London", "Greater London", 51.5074, -0.1278, "EC"),
|
||||
("Birmingham", "West Midlands", 52.4862, -1.8904, "B"),
|
||||
("Manchester", "Greater Manchester", 53.4808, -2.2426, "M"),
|
||||
("Glasgow", "Glasgow", 55.8642, -4.2518, "G"),
|
||||
("Liverpool", "Merseyside", 53.4084, -2.9916, "L"),
|
||||
("Bristol", "Bristol", 51.4545, -2.5879, "BS"),
|
||||
("Edinburgh", "Edinburgh", 55.9533, -3.1883, "EH"),
|
||||
("Leeds", "West Yorkshire", 53.8008, -1.5491, "LS"),
|
||||
("Sheffield", "South Yorkshire", 53.3811, -1.4701, "S"),
|
||||
("Newcastle upon Tyne", "Tyne and Wear", 54.9783, -1.6178, "NE"),
|
||||
("Nottingham", "Nottinghamshire", 52.9548, -1.1581, "NG"),
|
||||
("Cardiff", "Cardiff", 51.4816, -3.1791, "CF"),
|
||||
("Belfast", "Belfast", 54.5973, -5.9301, "BT"),
|
||||
("Brighton", "East Sussex", 50.8225, -0.1372, "BN"),
|
||||
("Leicester", "Leicestershire", 52.6369, -1.1398, "LE"),
|
||||
("Aberdeen", "Aberdeen", 57.1497, -2.0943, "AB"),
|
||||
("Portsmouth", "Hampshire", 50.8198, -1.0880, "PO"),
|
||||
("York", "North Yorkshire", 53.9599, -1.0873, "YO"),
|
||||
("Swansea", "Swansea", 51.6214, -3.9436, "SA"),
|
||||
("Oxford", "Oxfordshire", 51.7520, -1.2577, "OX"),
|
||||
("Cambridge", "Cambridgeshire", 52.2053, 0.1218, "CB"),
|
||||
("Exeter", "Devon", 50.7184, -3.5339, "EX"),
|
||||
("Bath", "Somerset", 51.3751, -2.3617, "BA"),
|
||||
("Reading", "Berkshire", 51.4543, -0.9781, "RG"),
|
||||
("Preston", "Lancashire", 53.7632, -2.7031, "PR"),
|
||||
("Coventry", "West Midlands", 52.4068, -1.5197, "CV"),
|
||||
("Hull", "East Yorkshire", 53.7676, -0.3274, "HU"),
|
||||
("Stoke-on-Trent", "Staffordshire", 53.0027, -2.1794, "ST"),
|
||||
("Wolverhampton", "West Midlands", 52.5870, -2.1288, "WV"),
|
||||
("Plymouth", "Devon", 50.3755, -4.1427, "PL"),
|
||||
("Derby", "Derbyshire", 52.9225, -1.4746, "DE"),
|
||||
("Sunderland", "Tyne and Wear", 54.9069, -1.3830, "SR"),
|
||||
("Southampton", "Hampshire", 50.9097, -1.4044, "SO"),
|
||||
("Norwich", "Norfolk", 52.6309, 1.2974, "NR"),
|
||||
("Bournemouth", "Dorset", 50.7192, -1.8808, "BH"),
|
||||
("Middlesbrough", "North Yorkshire", 54.5742, -1.2350, "TS"),
|
||||
("Blackpool", "Lancashire", 53.8175, -3.0357, "FY"),
|
||||
("Bolton", "Greater Manchester", 53.5785, -2.4299, "BL"),
|
||||
("Ipswich", "Suffolk", 52.0567, 1.1482, "IP"),
|
||||
("Telford", "Shropshire", 52.6784, -2.4453, "TF"),
|
||||
("Dundee", "Dundee", 56.4620, -2.9707, "DD"),
|
||||
("Peterborough", "Cambridgeshire", 52.5695, -0.2405, "PE"),
|
||||
("Huddersfield", "West Yorkshire", 53.6458, -1.7850, "HD"),
|
||||
("Luton", "Bedfordshire", 51.8787, -0.4200, "LU"),
|
||||
("Warrington", "Cheshire", 53.3900, -2.5970, "WA"),
|
||||
("Southend-on-Sea", "Essex", 51.5459, 0.7077, "SS"),
|
||||
("Swindon", "Wiltshire", 51.5557, -1.7797, "SN"),
|
||||
("Slough", "Berkshire", 51.5105, -0.5950, "SL"),
|
||||
("Watford", "Hertfordshire", 51.6565, -0.3903, "WD"),
|
||||
("Carlisle", "Cumbria", 54.8952, -2.9335, "CA")
|
||||
]
|
||||
|
||||
# Street name components for generating realistic street names
|
||||
street_prefixes = ["High", "Main", "Church", "Park", "Mill", "Station", "London", "Victoria", "Queen", "King", "North", "South", "East", "West", "New", "Old", "Castle", "Bridge", "Green", "Market", "School", "Manor", "Abbey", "Priory", "Cathedral", "University", "College", "Hospital", "Railway", "Canal", "River", "Forest", "Wood", "Hill", "Mount", "Valley", "Meadow", "Field", "Farm", "Garden", "Orchard", "Vineyard", "Grange", "Lodge", "Court", "Hall", "House", "Cottage", "Barn", "Mill", "Windmill", "Watermill", "Forge", "Quarry", "Mine", "Pit", "Well", "Spring", "Brook", "Stream", "Lake", "Pond", "Pool", "Reservoir", "Bay", "Cove", "Beach", "Cliff", "Rock", "Stone", "Granite", "Marble", "Slate", "Clay", "Sand", "Gravel", "Chalk", "Flint", "Coal", "Iron", "Steel", "Copper", "Silver", "Gold", "Tin", "Lead", "Zinc", "Brass", "Bronze", "Pewter", "Nickel", "Cobalt", "Chromium", "Titanium", "Aluminium", "Silicon", "Carbon", "Oxygen", "Hydrogen", "Nitrogen", "Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon"]
|
||||
street_suffixes = ["Street", "Road", "Lane", "Avenue", "Drive", "Boulevard", "Way", "Place", "Square", "Court", "Terrace", "Close", "Crescent", "Gardens", "Grove", "Mews", "Alley", "Walk", "Path", "Trail", "Hill", "Rise", "View", "Heights", "Park", "Green", "Meadow", "Field", "Common", "Heath", "Moor", "Down", "Fell", "Pike", "Tor", "Crag", "Cliff", "Ridge", "Edge", "Top", "Bottom", "Side", "End", "Corner", "Junction", "Cross", "Gate", "Bridge", "Ford", "Ferry", "Wharf", "Quay", "Dock", "Harbor", "Port", "Bay", "Cove", "Beach", "Shore", "Bank", "Strand", "Esplanade", "Parade", "Promenade", "Embankment", "Causeway", "Viaduct", "Tunnel", "Passage", "Arcade", "Gallery", "Mall", "Market", "Bazaar", "Fair", "Exchange", "Mart", "Emporium", "Center", "Circle", "Oval", "Triangle", "Pentagon", "Hexagon", "Octagon", "Circus", "Ring", "Loop", "Bend", "Curve", "Turn", "Twist", "Spiral", "Coil", "Helix", "Maze", "Labyrinth"]
|
||||
|
||||
# Facility descriptions by category
|
||||
category_descriptions = {
|
||||
1: [ # Recycling Bins
|
||||
"Public recycling point for paper, glass, plastic, and metal",
|
||||
"Community recycling station with separate bins for different materials",
|
||||
"Recycling center with facilities for household waste separation",
|
||||
"Public access recycling bins for common household recyclables",
|
||||
"Multi-material recycling point with clear instructions for proper sorting"
|
||||
],
|
||||
2: [ # e-Scooters
|
||||
"Dockless e-scooter rental station with multiple vehicles available",
|
||||
"E-scooter parking and charging zone for public use",
|
||||
"Designated e-scooter pickup and drop-off point",
|
||||
"E-scooter sharing station with app-based rental system",
|
||||
"Electric scooter hub with maintenance and charging facilities"
|
||||
],
|
||||
3: [ # Bike Share Stations
|
||||
"Public bicycle sharing station with multiple bikes available",
|
||||
"Bike rental hub with secure docking stations",
|
||||
"Community bike share point with regular and electric bicycles",
|
||||
"Cycle hire station with self-service rental system",
|
||||
"Bike sharing facility with maintenance and repair services"
|
||||
],
|
||||
4: [ # Public EV Charging Stations
|
||||
"Electric vehicle charging point with multiple connectors",
|
||||
"Fast-charging station for electric vehicles",
|
||||
"Public EV charging facility with covered waiting area",
|
||||
"Multi-vehicle electric charging hub with different power options",
|
||||
"EV charging station with renewable energy source"
|
||||
],
|
||||
5: [ # Battery Recycling Points
|
||||
"Dedicated collection point for used batteries of all sizes",
|
||||
"Battery recycling bin with separate compartments for different types",
|
||||
"Safe disposal facility for household and small electronics batteries",
|
||||
"Battery collection point with educational information about recycling",
|
||||
"Secure battery recycling station to prevent environmental contamination"
|
||||
],
|
||||
6: [ # Community Compost Bins
|
||||
"Neighborhood composting facility for food and garden waste",
|
||||
"Community compost bins with educational signage",
|
||||
"Public composting station with separate sections for different stages",
|
||||
"Shared compost facility managed by local volunteers",
|
||||
"Urban composting hub turning food waste into valuable soil"
|
||||
],
|
||||
7: [ # Solar-Powered Benches
|
||||
"Solar bench with USB charging ports and WiFi connectivity",
|
||||
"Public seating with integrated solar panels and device charging",
|
||||
"Smart bench powered by solar energy with digital information display",
|
||||
"Solar-powered rest area with phone charging capabilities",
|
||||
"Eco-friendly bench with solar panels and LED lighting"
|
||||
],
|
||||
8: [ # Green Roofs
|
||||
"Building with extensive green roof system visible from public areas",
|
||||
"Accessible green roof garden with native plant species",
|
||||
"Public building showcasing sustainable rooftop vegetation",
|
||||
"Green roof installation with educational tours available",
|
||||
"Biodiverse roof garden with insect habitats and rainwater collection"
|
||||
],
|
||||
9: [ # Public Water Refill Stations
|
||||
"Free water refill station to reduce plastic bottle usage",
|
||||
"Public drinking fountain with bottle filling capability",
|
||||
"Water refill point with filtered water options",
|
||||
"Accessible water station encouraging reusable bottles",
|
||||
"Community water dispenser with usage counter display"
|
||||
],
|
||||
10: [ # Waste Oil Collection Points
|
||||
"Cooking oil recycling point for residential use",
|
||||
"Used oil collection facility with secure containers",
|
||||
"Waste oil drop-off point for conversion to biodiesel",
|
||||
"Community oil recycling station with spill prevention measures",
|
||||
"Cooking oil collection facility with educational information"
|
||||
],
|
||||
11: [ # Book Swap Stations
|
||||
"Community book exchange point with weatherproof shelving",
|
||||
"Public book sharing library in repurposed phone box",
|
||||
"Free book swap station encouraging reading and reuse",
|
||||
"Neighborhood book exchange with rotating collection",
|
||||
"Little free library with take-one-leave-one system"
|
||||
],
|
||||
12: [ # Pollinator Gardens
|
||||
"Public garden designed to support bees and butterflies",
|
||||
"Pollinator-friendly planting area with native flowering species",
|
||||
"Community garden dedicated to supporting local insect populations",
|
||||
"Bee-friendly garden with educational signage about pollinators",
|
||||
"Urban wildflower meadow supporting biodiversity"
|
||||
],
|
||||
13: [ # E-Waste Collection Bins
|
||||
"Secure collection point for electronic waste and small appliances",
|
||||
"E-waste recycling bin for phones, computers, and small electronics",
|
||||
"Electronic waste drop-off point with data security assurance",
|
||||
"Community e-waste collection facility with regular collection schedule",
|
||||
"Dedicated bin for responsible disposal of electronic items"
|
||||
],
|
||||
14: [ # Clothing Donation Bins
|
||||
"Textile recycling point for clothes and household fabrics",
|
||||
"Clothing donation bin supporting local charities",
|
||||
"Secure collection point for reusable clothing and textiles",
|
||||
"Community clothing recycling bin with regular collection",
|
||||
"Textile donation point preventing landfill waste"
|
||||
],
|
||||
15: [ # Community Tool Libraries
|
||||
"Tool lending library for community use and sharing",
|
||||
"Shared equipment facility reducing need for individual ownership",
|
||||
"Community resource center for borrowing tools and equipment",
|
||||
"Tool sharing hub with membership system and workshops",
|
||||
"Public tool library with wide range of equipment available"
|
||||
],
|
||||
16: [ # Urban Farms
|
||||
"Community-run urban farm providing local produce",
|
||||
"City farming project with volunteer opportunities",
|
||||
"Urban agriculture site with educational programs",
|
||||
"Local food growing initiative in repurposed urban space",
|
||||
"Community garden with vegetable plots and fruit trees"
|
||||
],
|
||||
17: [ # Rainwater Harvesting Systems
|
||||
"Public demonstration of rainwater collection for irrigation",
|
||||
"Rainwater harvesting system with educational displays",
|
||||
"Community rainwater collection facility for shared gardens",
|
||||
"Visible rainwater storage and filtration system",
|
||||
"Urban water conservation project with storage tanks"
|
||||
]
|
||||
}
|
||||
|
||||
# Status comments by category
|
||||
status_comments = {
|
||||
1: [ # Recycling Bins
|
||||
"Recently emptied and cleaned",
|
||||
"Some bins are nearly full",
|
||||
"All bins in good condition",
|
||||
"Paper bin is currently full",
|
||||
"New signage installed to improve sorting"
|
||||
],
|
||||
2: [ # e-Scooters
|
||||
"All scooters fully charged",
|
||||
"Three scooters currently available",
|
||||
"Maintenance scheduled for next week",
|
||||
"New scooters added to this location",
|
||||
"High usage area, scooters frequently unavailable"
|
||||
],
|
||||
3: [ # Bike Share Stations
|
||||
"All docking stations operational",
|
||||
"Five bikes currently available",
|
||||
"Some bikes need maintenance",
|
||||
"New electric bikes added",
|
||||
"Popular station with high turnover"
|
||||
],
|
||||
4: [ # Public EV Charging Stations
|
||||
"All charging points operational",
|
||||
"Fast charger currently under repair",
|
||||
"Peak usage during business hours",
|
||||
"New charging point added last month",
|
||||
"Payment system recently upgraded"
|
||||
],
|
||||
5: [ # Battery Recycling Points
|
||||
"Collection bin recently emptied",
|
||||
"Secure container in good condition",
|
||||
"New signage explaining battery types",
|
||||
"High usage from local businesses",
|
||||
"Additional capacity added"
|
||||
],
|
||||
6: [ # Community Compost Bins
|
||||
"Compost ready for collection",
|
||||
"Needs more brown material",
|
||||
"Recently turned and aerated",
|
||||
"New bins added to increase capacity",
|
||||
"Volunteer day scheduled for maintenance"
|
||||
],
|
||||
7: [ # Solar-Powered Benches
|
||||
"All charging ports working",
|
||||
"Solar panels recently cleaned",
|
||||
"WiFi currently unavailable",
|
||||
"LED lights need replacement",
|
||||
"High usage during lunch hours"
|
||||
],
|
||||
8: [ # Green Roofs
|
||||
"Plants thriving after recent rain",
|
||||
"Maintenance scheduled next month",
|
||||
"New species added to increase biodiversity",
|
||||
"Irrigation system working well",
|
||||
"Open for public tours on weekends"
|
||||
],
|
||||
9: [ # Public Water Refill Stations
|
||||
"Water quality tested weekly",
|
||||
"Fountain cleaned daily",
|
||||
"Bottle filler counter shows high usage",
|
||||
"New filter installed recently",
|
||||
"Popular during summer months"
|
||||
],
|
||||
10: [ # Waste Oil Collection Points
|
||||
"Container recently emptied",
|
||||
"Secure lid in good condition",
|
||||
"New funnel system installed",
|
||||
"Collection schedule posted",
|
||||
"Area kept clean and tidy"
|
||||
],
|
||||
11: [ # Book Swap Stations
|
||||
"Good selection currently available",
|
||||
"Children's books needed",
|
||||
"Recently reorganized by volunteers",
|
||||
"Weatherproof cover working well",
|
||||
"High turnover of popular titles"
|
||||
],
|
||||
12: [ # Pollinator Gardens
|
||||
"Plants in full bloom",
|
||||
"Many bees and butterflies observed",
|
||||
"New native species planted",
|
||||
"Volunteer day for maintenance scheduled",
|
||||
"Educational tours available"
|
||||
],
|
||||
13: [ # E-Waste Collection Bins
|
||||
"Bin recently emptied",
|
||||
"Secure deposit system working",
|
||||
"Collection schedule posted",
|
||||
"New items accepted now include small appliances",
|
||||
"Data destruction guaranteed"
|
||||
],
|
||||
14: [ # Clothing Donation Bins
|
||||
"Bin recently emptied",
|
||||
"Clean and well-maintained",
|
||||
"High quality donations appreciated",
|
||||
"Winter clothing especially needed",
|
||||
"Please bag items before donating"
|
||||
],
|
||||
15: [ # Community Tool Libraries
|
||||
"New inventory system implemented",
|
||||
"Popular tools often unavailable on weekends",
|
||||
"Tool maintenance workshop scheduled",
|
||||
"New donations recently added to collection",
|
||||
"Extended hours during summer"
|
||||
],
|
||||
16: [ # Urban Farms
|
||||
"Seasonal produce currently available",
|
||||
"Volunteer opportunities posted",
|
||||
"Educational workshops on weekends",
|
||||
"New growing area being developed",
|
||||
"Composting system recently expanded"
|
||||
],
|
||||
17: [ # Rainwater Harvesting Systems
|
||||
"System working efficiently after recent rainfall",
|
||||
"Water quality monitoring in place",
|
||||
"Educational tours available by appointment",
|
||||
"System capacity recently expanded",
|
||||
"Used for irrigation of nearby community garden"
|
||||
]
|
||||
}
|
||||
|
||||
# Generate a realistic UK postcode based on area code
|
||||
def generate_postcode(area_code):
|
||||
# Format: Area + District + Space + Sector + Unit
|
||||
# e.g., M1 1AA or SW1A 1AA
|
||||
district = random.randint(1, 99)
|
||||
sector = random.randint(1, 9)
|
||||
unit = ''.join(random.choices('ABCDEFGHJKLMNPQRSTUVWXYZ', k=2)) # Excluding I and O as they're not used
|
||||
|
||||
if len(area_code) == 1:
|
||||
return f"{area_code}{district} {sector}{unit}"
|
||||
else:
|
||||
return f"{area_code}{district} {sector}{unit}"
|
||||
|
||||
# Generate a realistic street name
|
||||
def generate_street_name():
|
||||
prefix = random.choice(street_prefixes)
|
||||
suffix = random.choice(street_suffixes)
|
||||
return f"{prefix} {suffix}"
|
||||
|
||||
# Generate a realistic house number
|
||||
def generate_house_number():
|
||||
# 80% chance of a simple number, 20% chance of a letter suffix or unit
|
||||
if random.random() < 0.8:
|
||||
return str(random.randint(1, 200))
|
||||
else:
|
||||
options = [
|
||||
f"{random.randint(1, 200)}{random.choice('ABCDEFG')}", # e.g., 42A
|
||||
f"Unit {random.randint(1, 20)}",
|
||||
f"Flat {random.randint(1, 50)}",
|
||||
f"Suite {random.randint(1, 10)}"
|
||||
]
|
||||
return random.choice(options)
|
||||
|
||||
# Add small random variation to coordinates to avoid facilities at exact same location
|
||||
def vary_coordinates(lat, lng):
|
||||
# Add variation of up to ~500 meters
|
||||
lat_variation = random.uniform(-0.004, 0.004)
|
||||
lng_variation = random.uniform(-0.006, 0.006)
|
||||
return lat + lat_variation, lng + lng_variation
|
||||
|
||||
# Generate facility title based on category and location
|
||||
def generate_title(category_name, location_name, street_name):
|
||||
templates = [
|
||||
f"{location_name} {category_name}",
|
||||
f"{category_name} at {street_name}",
|
||||
f"{street_name} {category_name}",
|
||||
f"Community {category_name} {location_name}",
|
||||
f"{location_name} Central {category_name}",
|
||||
f"{location_name} {street_name} {category_name}"
|
||||
]
|
||||
return random.choice(templates)
|
||||
|
||||
# Create a log file to track progress
|
||||
log_file = open("facility_generation_log.txt", "w")
|
||||
log_file.write(f"Starting facility generation at {datetime.now()}\n")
|
||||
log_file.write(f"Target: 1000 new facilities\n\n")
|
||||
|
||||
# Create a CSV file to store all generated facilities for reference
|
||||
csv_file = open("generated_facilities.csv", "w", newline='')
|
||||
csv_writer = csv.writer(csv_file)
|
||||
csv_writer.writerow(["ID", "Title", "Category", "Description", "Address", "Postcode", "Latitude", "Longitude", "Contributor"])
|
||||
|
||||
# Prepare for batch insertion to improve performance
|
||||
facilities_to_insert = []
|
||||
status_comments_to_insert = []
|
||||
|
||||
# Track unique titles to avoid duplicates
|
||||
existing_titles = set()
|
||||
cursor.execute("SELECT title FROM ecoFacilities")
|
||||
for row in cursor.fetchall():
|
||||
existing_titles.add(row[0])
|
||||
|
||||
# Generate 1000 facilities
|
||||
num_facilities = 1000
|
||||
facilities_created = 0
|
||||
|
||||
log_file.write("Generating facilities...\n")
|
||||
|
||||
while facilities_created < num_facilities:
|
||||
# Select a random location
|
||||
location = random.choice(uk_locations)
|
||||
location_name, county, base_lat, base_lng, postcode_area = location
|
||||
|
||||
# Generate 5-25 facilities per location to create clusters
|
||||
facilities_per_location = min(random.randint(5, 25), num_facilities - facilities_created)
|
||||
|
||||
for _ in range(facilities_per_location):
|
||||
# Select a random category
|
||||
category_id = random.choice(list(categories.keys()))
|
||||
category_name = categories[category_id]
|
||||
|
||||
# Generate address components
|
||||
street_name = generate_street_name()
|
||||
house_number = generate_house_number()
|
||||
lat, lng = vary_coordinates(base_lat, base_lng)
|
||||
postcode = generate_postcode(postcode_area)
|
||||
|
||||
# Generate title
|
||||
title_base = generate_title(category_name, location_name, street_name)
|
||||
title = title_base
|
||||
|
||||
# Ensure title is unique by adding a suffix if needed
|
||||
suffix = 2
|
||||
while title in existing_titles:
|
||||
title = f"{title_base} {suffix}"
|
||||
suffix += 1
|
||||
|
||||
existing_titles.add(title)
|
||||
|
||||
# Select description
|
||||
description = random.choice(category_descriptions[category_id])
|
||||
|
||||
# Select contributor
|
||||
contributor_id = random.choice(user_ids)
|
||||
|
||||
# Add to batch for insertion
|
||||
facilities_to_insert.append((
|
||||
title,
|
||||
category_id,
|
||||
description,
|
||||
house_number,
|
||||
street_name,
|
||||
county,
|
||||
location_name,
|
||||
postcode,
|
||||
lng,
|
||||
lat,
|
||||
contributor_id
|
||||
))
|
||||
|
||||
# Log progress periodically
|
||||
facilities_created += 1
|
||||
if facilities_created % 100 == 0:
|
||||
log_message = f"Generated {facilities_created} facilities so far..."
|
||||
print(log_message)
|
||||
log_file.write(log_message + "\n")
|
||||
|
||||
if facilities_created >= num_facilities:
|
||||
break
|
||||
|
||||
# Insert facilities in batches for better performance
|
||||
log_file.write("\nInserting facilities into database...\n")
|
||||
print("Inserting facilities into database...")
|
||||
|
||||
batch_size = 50
|
||||
for i in range(0, len(facilities_to_insert), batch_size):
|
||||
batch = facilities_to_insert[i:i+batch_size]
|
||||
cursor.executemany("""
|
||||
INSERT INTO ecoFacilities
|
||||
(title, category, description, houseNumber, streetName, county, town, postcode, lng, lat, contributor)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", batch)
|
||||
|
||||
# Get the IDs of the inserted facilities
|
||||
cursor.execute("SELECT last_insert_rowid()")
|
||||
last_id = cursor.fetchone()[0]
|
||||
first_id_in_batch = last_id - len(batch) + 1
|
||||
|
||||
# Generate status comments for each facility
|
||||
for j, facility in enumerate(batch):
|
||||
facility_id = first_id_in_batch + j
|
||||
category_id = facility[1] # Category ID is the second element
|
||||
|
||||
# Write to CSV for reference
|
||||
csv_writer.writerow([
|
||||
facility_id,
|
||||
facility[0], # title
|
||||
categories[category_id], # category name
|
||||
facility[2], # description
|
||||
f"{facility[3]} {facility[4]}, {facility[6]}, {facility[5]}", # address
|
||||
facility[7], # postcode
|
||||
facility[9], # lat
|
||||
facility[8], # lng
|
||||
facility[10] # contributor
|
||||
])
|
||||
|
||||
# Decide how many status comments to add (0-3)
|
||||
num_comments = random.choices([0, 1, 2, 3], weights=[30, 40, 20, 10])[0]
|
||||
|
||||
if num_comments > 0:
|
||||
# Get relevant comments for this category
|
||||
relevant_comments = status_comments.get(category_id, status_comments[1]) # Default to recycling bin comments
|
||||
|
||||
# Select random comments without repetition
|
||||
selected_comments = random.sample(relevant_comments, min(num_comments, len(relevant_comments)))
|
||||
|
||||
# Add to batch for insertion
|
||||
for comment in selected_comments:
|
||||
status_comments_to_insert.append((facility_id, comment))
|
||||
|
||||
# Commit after each batch
|
||||
conn.commit()
|
||||
|
||||
log_message = f"Inserted batch {i//batch_size + 1}/{(len(facilities_to_insert)-1)//batch_size + 1}"
|
||||
print(log_message)
|
||||
log_file.write(log_message + "\n")
|
||||
|
||||
# Insert status comments in batches
|
||||
if status_comments_to_insert:
|
||||
log_file.write("\nInserting status comments...\n")
|
||||
print("Inserting status comments...")
|
||||
|
||||
for i in range(0, len(status_comments_to_insert), batch_size):
|
||||
batch = status_comments_to_insert[i:i+batch_size]
|
||||
cursor.executemany("""
|
||||
INSERT INTO ecoFacilityStatus (facilityId, statusComment)
|
||||
VALUES (?, ?)
|
||||
""", batch)
|
||||
conn.commit()
|
||||
|
||||
log_message = f"Inserted comment batch {i//batch_size + 1}/{(len(status_comments_to_insert)-1)//batch_size + 1}"
|
||||
print(log_message)
|
||||
log_file.write(log_message + "\n")
|
||||
|
||||
# Get final counts
|
||||
cursor.execute("SELECT COUNT(*) FROM ecoFacilities")
|
||||
total_facilities = cursor.fetchone()[0]
|
||||
|
||||
cursor.execute("SELECT COUNT(*) FROM ecoFacilityStatus")
|
||||
total_comments = cursor.fetchone()[0]
|
||||
|
||||
# Log completion
|
||||
completion_message = f"\nGeneration complete at {datetime.now()}"
|
||||
print(completion_message)
|
||||
log_file.write(completion_message + "\n")
|
||||
|
||||
summary = f"Total facilities in database: {total_facilities}\n"
|
||||
summary += f"Total status comments in database: {total_comments}\n"
|
||||
summary += f"Generated facilities saved to generated_facilities.csv for reference"
|
||||
|
||||
print(summary)
|
||||
log_file.write(summary)
|
||||
|
||||
# Close connections
|
||||
log_file.close()
|
||||
csv_file.close()
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print("\nSuccessfully added 1000 new ecological facilities to the database.")
|
||||
print("A detailed log and CSV export have been created for reference.")
|
||||
79
Databases/generate_users.php
Normal file
79
Databases/generate_users.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
// Connect to the SQLite database
|
||||
$db = new PDO('sqlite:Databases/ecobuddy.sqlite');
|
||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
// List of real first names for usernames
|
||||
$firstNames = [
|
||||
'James', 'John', 'Robert', 'Michael', 'William', 'David', 'Richard', 'Joseph', 'Thomas', 'Charles',
|
||||
'Christopher', 'Daniel', 'Matthew', 'Anthony', 'Mark', 'Donald', 'Steven', 'Paul', 'Andrew', 'Joshua',
|
||||
'Kenneth', 'Kevin', 'Brian', 'George', 'Timothy', 'Ronald', 'Edward', 'Jason', 'Jeffrey', 'Ryan',
|
||||
'Jacob', 'Gary', 'Nicholas', 'Eric', 'Jonathan', 'Stephen', 'Larry', 'Justin', 'Scott', 'Brandon',
|
||||
'Benjamin', 'Samuel', 'Gregory', 'Alexander', 'Frank', 'Patrick', 'Raymond', 'Jack', 'Dennis', 'Jerry',
|
||||
'Tyler', 'Aaron', 'Jose', 'Adam', 'Nathan', 'Henry', 'Douglas', 'Zachary', 'Peter', 'Kyle',
|
||||
'Ethan', 'Walter', 'Noah', 'Jeremy', 'Christian', 'Keith', 'Roger', 'Terry', 'Gerald', 'Harold',
|
||||
'Sean', 'Austin', 'Carl', 'Arthur', 'Lawrence', 'Dylan', 'Jesse', 'Jordan', 'Bryan', 'Billy',
|
||||
'Joe', 'Bruce', 'Gabriel', 'Logan', 'Albert', 'Willie', 'Alan', 'Juan', 'Wayne', 'Elijah',
|
||||
'Randy', 'Roy', 'Vincent', 'Ralph', 'Eugene', 'Russell', 'Bobby', 'Mason', 'Philip', 'Louis'
|
||||
];
|
||||
|
||||
// List of common words for password generation
|
||||
$words = [
|
||||
'Apple', 'Banana', 'Cherry', 'Dragon', 'Eagle', 'Forest', 'Garden', 'Harbor', 'Island', 'Jungle',
|
||||
'Kingdom', 'Lemon', 'Mountain', 'Nature', 'Ocean', 'Planet', 'Queen', 'River', 'Summer', 'Tiger',
|
||||
'Universe', 'Volcano', 'Winter', 'Yellow', 'Zebra', 'Castle', 'Diamond', 'Emerald', 'Flower', 'Galaxy',
|
||||
'Horizon', 'Iceberg', 'Journey', 'Knight', 'Legend', 'Meadow', 'Nebula', 'Oasis', 'Palace', 'Quasar',
|
||||
'Rainbow', 'Sapphire', 'Thunder', 'Unicorn', 'Victory', 'Whisper', 'Xylophone', 'Yacht', 'Zephyr', 'Autumn',
|
||||
'Breeze', 'Cascade', 'Dolphin', 'Eclipse', 'Falcon', 'Glacier', 'Harmony', 'Infinity', 'Jasmine', 'Kaleidoscope',
|
||||
'Lighthouse', 'Mirage', 'Nightfall', 'Orchard', 'Phoenix', 'Quicksilver', 'Radiance', 'Serenity', 'Twilight', 'Umbrella'
|
||||
];
|
||||
|
||||
// Check if we already have users with these names
|
||||
$existingUsers = [];
|
||||
$stmt = $db->query("SELECT username FROM ecoUser");
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$existingUsers[] = $row['username'];
|
||||
}
|
||||
|
||||
// Prepare the SQL statement for inserting users
|
||||
$insertStmt = $db->prepare("INSERT INTO ecoUser (username, password, userType) VALUES (?, ?, ?)");
|
||||
|
||||
// Create a file to store usernames and passwords
|
||||
$file = fopen("user_credentials.txt", "w");
|
||||
fwrite($file, "Username,Password\n");
|
||||
|
||||
// Generate 50 users
|
||||
$usersAdded = 0;
|
||||
$usedNames = [];
|
||||
shuffle($firstNames);
|
||||
|
||||
foreach ($firstNames as $name) {
|
||||
if ($usersAdded >= 50) break;
|
||||
|
||||
// Skip if the name is already in the database
|
||||
if (in_array($name, $existingUsers) || in_array($name, $usedNames)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate password in format (Word)(Word)(Word)(Digit)
|
||||
$password = $words[array_rand($words)] . $words[array_rand($words)] . $words[array_rand($words)] . rand(0, 9);
|
||||
|
||||
// Hash the password using SHA-256
|
||||
$hashedPassword = hash('sha256', $password);
|
||||
|
||||
// Insert the user into the database (userType 2 is for standard users)
|
||||
$insertStmt->execute([$name, $hashedPassword, 2]);
|
||||
|
||||
// Write the credentials to the file
|
||||
fwrite($file, "$name,$password\n");
|
||||
|
||||
$usedNames[] = $name;
|
||||
$usersAdded++;
|
||||
|
||||
echo "Added user: $name\n";
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
|
||||
echo "\nSuccessfully added $usersAdded users to the database.\n";
|
||||
echo "Usernames and passwords have been saved to user_credentials.txt\n";
|
||||
79
Databases/generate_users.py
Normal file
79
Databases/generate_users.py
Normal file
@@ -0,0 +1,79 @@
|
||||
import sqlite3
|
||||
import random
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
# Connect to the SQLite database
|
||||
conn = sqlite3.connect('Databases/ecobuddy.sqlite')
|
||||
cursor = conn.cursor()
|
||||
|
||||
# List of real first names for usernames
|
||||
first_names = [
|
||||
'James', 'John', 'Robert', 'Michael', 'William', 'David', 'Richard', 'Joseph', 'Thomas', 'Charles',
|
||||
'Christopher', 'Daniel', 'Matthew', 'Anthony', 'Mark', 'Donald', 'Steven', 'Paul', 'Andrew', 'Joshua',
|
||||
'Kenneth', 'Kevin', 'Brian', 'George', 'Timothy', 'Ronald', 'Edward', 'Jason', 'Jeffrey', 'Ryan',
|
||||
'Jacob', 'Gary', 'Nicholas', 'Eric', 'Jonathan', 'Stephen', 'Larry', 'Justin', 'Scott', 'Brandon',
|
||||
'Benjamin', 'Samuel', 'Gregory', 'Alexander', 'Frank', 'Patrick', 'Raymond', 'Jack', 'Dennis', 'Jerry',
|
||||
'Tyler', 'Aaron', 'Jose', 'Adam', 'Nathan', 'Henry', 'Douglas', 'Zachary', 'Peter', 'Kyle',
|
||||
'Ethan', 'Walter', 'Noah', 'Jeremy', 'Christian', 'Keith', 'Roger', 'Terry', 'Gerald', 'Harold',
|
||||
'Sean', 'Austin', 'Carl', 'Arthur', 'Lawrence', 'Dylan', 'Jesse', 'Jordan', 'Bryan', 'Billy',
|
||||
'Joe', 'Bruce', 'Gabriel', 'Logan', 'Albert', 'Willie', 'Alan', 'Juan', 'Wayne', 'Elijah',
|
||||
'Randy', 'Roy', 'Vincent', 'Ralph', 'Eugene', 'Russell', 'Bobby', 'Mason', 'Philip', 'Louis'
|
||||
]
|
||||
|
||||
# List of common words for password generation
|
||||
words = [
|
||||
'Apple', 'Banana', 'Cherry', 'Dragon', 'Eagle', 'Forest', 'Garden', 'Harbor', 'Island', 'Jungle',
|
||||
'Kingdom', 'Lemon', 'Mountain', 'Nature', 'Ocean', 'Planet', 'Queen', 'River', 'Summer', 'Tiger',
|
||||
'Universe', 'Volcano', 'Winter', 'Yellow', 'Zebra', 'Castle', 'Diamond', 'Emerald', 'Flower', 'Galaxy',
|
||||
'Horizon', 'Iceberg', 'Journey', 'Knight', 'Legend', 'Meadow', 'Nebula', 'Oasis', 'Palace', 'Quasar',
|
||||
'Rainbow', 'Sapphire', 'Thunder', 'Unicorn', 'Victory', 'Whisper', 'Xylophone', 'Yacht', 'Zephyr', 'Autumn',
|
||||
'Breeze', 'Cascade', 'Dolphin', 'Eclipse', 'Falcon', 'Glacier', 'Harmony', 'Infinity', 'Jasmine', 'Kaleidoscope',
|
||||
'Lighthouse', 'Mirage', 'Nightfall', 'Orchard', 'Phoenix', 'Quicksilver', 'Radiance', 'Serenity', 'Twilight', 'Umbrella'
|
||||
]
|
||||
|
||||
# Check if we already have users with these names
|
||||
cursor.execute("SELECT username FROM ecoUser")
|
||||
existing_users = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# Create a file to store usernames and passwords
|
||||
with open("user_credentials.txt", "w") as file:
|
||||
file.write("Username,Password\n")
|
||||
|
||||
# Generate 50 users
|
||||
users_added = 0
|
||||
used_names = []
|
||||
random.shuffle(first_names)
|
||||
|
||||
for name in first_names:
|
||||
if users_added >= 50:
|
||||
break
|
||||
|
||||
# Skip if the name is already in the database
|
||||
if name in existing_users or name in used_names:
|
||||
continue
|
||||
|
||||
# Generate password in format (Word)(Word)(Word)(Digit)
|
||||
password = random.choice(words) + random.choice(words) + random.choice(words) + str(random.randint(0, 9))
|
||||
|
||||
# Hash the password using SHA-256
|
||||
hashed_password = hashlib.sha256(password.encode()).hexdigest()
|
||||
|
||||
# Insert the user into the database (userType 2 is for standard users)
|
||||
cursor.execute("INSERT INTO ecoUser (username, password, userType) VALUES (?, ?, ?)",
|
||||
(name, hashed_password, 2))
|
||||
|
||||
# Write the credentials to the file
|
||||
file.write(f"{name},{password}\n")
|
||||
|
||||
used_names.append(name)
|
||||
users_added += 1
|
||||
|
||||
print(f"Added user: {name}")
|
||||
|
||||
# Commit the changes and close the connection
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print(f"\nSuccessfully added {users_added} users to the database.")
|
||||
print("Usernames and passwords have been saved to user_credentials.txt")
|
||||
1001
Databases/generated_facilities.csv
Normal file
1001
Databases/generated_facilities.csv
Normal file
File diff suppressed because it is too large
Load Diff
51
Databases/user_credentials.txt
Normal file
51
Databases/user_credentials.txt
Normal file
@@ -0,0 +1,51 @@
|
||||
Username,Password
|
||||
Dylan,MirageAutumnUmbrella7
|
||||
Lawrence,MirageVictoryKingdom5
|
||||
Bryan,EmeraldOrchardLegend3
|
||||
Alan,ThunderOceanDiamond2
|
||||
Frank,XylophoneVictoryHarmony3
|
||||
Logan,NatureSerenityXylophone5
|
||||
Jerry,LighthousePhoenixYellow8
|
||||
Harold,IcebergGlacierTiger8
|
||||
Keith,YachtJourneyGarden4
|
||||
Arthur,VictoryOrchardFlower0
|
||||
Louis,FlowerNebulaNature3
|
||||
Paul,LegendLegendYacht4
|
||||
Aaron,RiverCascadeApple3
|
||||
George,MeadowBreezePalace4
|
||||
Carl,RadianceMirageQuasar2
|
||||
Kenneth,IcebergPlanetHorizon8
|
||||
Daniel,BreezeXylophoneGalaxy5
|
||||
Ronald,PhoenixThunderZephyr2
|
||||
Benjamin,NatureVolcanoNebula8
|
||||
Joe,UnicornSapphireHorizon1
|
||||
Larry,IslandZebraApple6
|
||||
Zachary,SapphireUnicornJasmine0
|
||||
Willie,UmbrellaVictoryHorizon8
|
||||
Anthony,QueenZebraNebula9
|
||||
Michael,TigerMountainNightfall8
|
||||
Vincent,InfinityHorizonQuicksilver8
|
||||
Roger,WinterXylophonePalace8
|
||||
Kyle,IcebergDolphinDragon9
|
||||
Henry,HarmonyKnightPalace7
|
||||
Eugene,JourneyThunderPalace0
|
||||
Billy,ThunderThunderQuicksilver9
|
||||
Peter,OrchardJasmineVictory4
|
||||
Christopher,QueenThunderAutumn5
|
||||
Adam,SummerUnicornThunder7
|
||||
Nathan,SerenityOrchardThunder2
|
||||
Edward,MeadowGalaxyYellow6
|
||||
Eric,DolphinNebulaYacht8
|
||||
Brian,CastleFlowerGlacier4
|
||||
Alexander,ForestSapphireZebra4
|
||||
Andrew,GalaxyLemonApple0
|
||||
Brandon,HarmonyTigerHarmony2
|
||||
Russell,CherryZebraQuicksilver8
|
||||
Jack,OrchardZephyrSapphire8
|
||||
Jose,BananaJungleSerenity8
|
||||
Jacob,KaleidoscopeEmeraldJasmine5
|
||||
Dennis,KnightFlowerRainbow2
|
||||
Donald,WhisperQuicksilverCastle1
|
||||
William,ApplePalaceSummer6
|
||||
Patrick,CastleInfinityPhoenix9
|
||||
Timothy,YellowEagleSummer0
|
||||
8
MVCTemplate/MVCtemplateWithBasicLogin/.idea/.gitignore
generated
vendored
8
MVCTemplate/MVCtemplateWithBasicLogin/.idea/.gitignore
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
@@ -1 +0,0 @@
|
||||
MVCtemplate
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||
</project>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" />
|
||||
</project>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/MVCtemplate.iml" filepath="$PROJECT_DIR$/.idea/MVCtemplate.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="5.5.0" />
|
||||
</project>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<component name="DependencyValidationManager">
|
||||
<state>
|
||||
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
||||
</state>
|
||||
</component>
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php require('template/header.phtml') ?>
|
||||
|
||||
<h3>Welcome to the web-site </h3>
|
||||
|
||||
<h3>A template for web-site development using the <i>Model-View-Controller</i> design pattern and <a href="http://www.getbootstrap.com/css"><i>Bootstrap</i></a>.</h3>
|
||||
<p>The <i>Views/template</i> directory contains a <i>header.phtl</i> and a <i>footer.phtml</i> which should be included on every new page generated.
|
||||
To add additional pages just edit the file <i>header.phtml</i> to add the extra link and then add a new <i>Controller (pageN.php)</i> and a new <i>View (pageN.phtml)</i>, for each page required.<p/>
|
||||
<p>The <i>Model</i> code files are placed in the <i>Models</i> directory.</p>
|
||||
<p>Do not change any of the css files in the <i>css</> directory!<p>
|
||||
|
||||
<?php require('template/footer.phtml') ?>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php require('template/header.phtml') ?>
|
||||
|
||||
<h3>Welcome to Page1</h3>
|
||||
|
||||
<?php require('template/footer.phtml') ?>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php require('template/header.phtml') ?>
|
||||
|
||||
<h3>Welcome to Page2</h3>
|
||||
|
||||
<?php require('template/footer.phtml') ?>
|
||||
@@ -1,15 +0,0 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div class-"row">
|
||||
<div id="footer" class="col-xs-12">
|
||||
<p>Web-site development using the MVC design pattern and the Bootstrap CSS framework</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Bootstrap core JavaScript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,68 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="/css/bootstrap.css" rel="stylesheet">
|
||||
<!-- Bootstrap theme -->
|
||||
<link href="/css/bootstrap-theme.css" rel="stylesheet">
|
||||
<link href="/css/my-style.css" rel="stylesheet">
|
||||
|
||||
<title>Server-Side Programming - <?php echo $view->pageTitle; ?></title>
|
||||
</head>
|
||||
|
||||
<body role=""document">
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div id="title" class="col-xs-12">
|
||||
<img src="images/new_uos_logo.jpg" alt="Salford University" />
|
||||
<div class="pull-right"> <h1><?php echo $view->pageTitle ?> </h1></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div id="menu" class="col-xs-6 col-sm-3 col-md-2">
|
||||
<ul class="nav navbar_default nav-stacked">
|
||||
|
||||
</ul>
|
||||
<?php
|
||||
|
||||
if (!isset($_SESSION["login"])) {
|
||||
echo '
|
||||
<form method="post" action="" class="form text-primary">
|
||||
<label for="username">Username</label>
|
||||
<input type="text" name="username">
|
||||
<label for="password">Password</label>
|
||||
<input type="text" name="password">
|
||||
<input type="submit" name="loginbutton" value="Login">
|
||||
|
||||
</form>';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '
|
||||
<form method="post" action="" class="form text-primary">
|
||||
<input type="submit" name="logoutbutton" value="Logout">
|
||||
</form>';
|
||||
}
|
||||
?>
|
||||
|
||||
<li><a href="index.php">Home</a></li>
|
||||
<li><a href="page1.php">Page1</a></li>
|
||||
<li><a href="page2.php">Page2</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="content" class="col-xs-6 col-sm-9 col-md-10">
|
||||
|
||||
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap v3.1.1 (http://getbootstrap.com)
|
||||
* Copyright 2011-2014 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
.btn-default,
|
||||
.btn-primary,
|
||||
.btn-success,
|
||||
.btn-info,
|
||||
.btn-warning,
|
||||
.btn-danger {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-primary:active,
|
||||
.btn-success:active,
|
||||
.btn-info:active,
|
||||
.btn-warning:active,
|
||||
.btn-danger:active,
|
||||
.btn-default.active,
|
||||
.btn-primary.active,
|
||||
.btn-success.active,
|
||||
.btn-info.active,
|
||||
.btn-warning.active,
|
||||
.btn-danger.active {
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
}
|
||||
.btn:active,
|
||||
.btn.active {
|
||||
background-image: none;
|
||||
}
|
||||
.btn-default {
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dbdbdb;
|
||||
border-color: #ccc;
|
||||
}
|
||||
.btn-default:hover,
|
||||
.btn-default:focus {
|
||||
background-color: #e0e0e0;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-default.active {
|
||||
background-color: #e0e0e0;
|
||||
border-color: #dbdbdb;
|
||||
}
|
||||
.btn-primary {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #2b669a;
|
||||
}
|
||||
.btn-primary:hover,
|
||||
.btn-primary:focus {
|
||||
background-color: #2d6ca2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-primary:active,
|
||||
.btn-primary.active {
|
||||
background-color: #2d6ca2;
|
||||
border-color: #2b669a;
|
||||
}
|
||||
.btn-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-success:hover,
|
||||
.btn-success:focus {
|
||||
background-color: #419641;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-success:active,
|
||||
.btn-success.active {
|
||||
background-color: #419641;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-info:hover,
|
||||
.btn-info:focus {
|
||||
background-color: #2aabd2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-info:active,
|
||||
.btn-info.active {
|
||||
background-color: #2aabd2;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-warning:hover,
|
||||
.btn-warning:focus {
|
||||
background-color: #eb9316;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-warning:active,
|
||||
.btn-warning.active {
|
||||
background-color: #eb9316;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.btn-danger:hover,
|
||||
.btn-danger:focus {
|
||||
background-color: #c12e2a;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-danger:active,
|
||||
.btn-danger.active {
|
||||
background-color: #c12e2a;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.thumbnail,
|
||||
.img-thumbnail {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.dropdown-menu > li > a:hover,
|
||||
.dropdown-menu > li > a:focus {
|
||||
background-color: #e8e8e8;
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.dropdown-menu > .active > a,
|
||||
.dropdown-menu > .active > a:hover,
|
||||
.dropdown-menu > .active > a:focus {
|
||||
background-color: #357ebd;
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.navbar-default {
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.navbar-default .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.navbar-brand,
|
||||
.navbar-nav > li > a {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
|
||||
}
|
||||
.navbar-inverse {
|
||||
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.navbar-inverse .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);
|
||||
background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
}
|
||||
.navbar-inverse .navbar-brand,
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
|
||||
}
|
||||
.navbar-static-top,
|
||||
.navbar-fixed-top,
|
||||
.navbar-fixed-bottom {
|
||||
border-radius: 0;
|
||||
}
|
||||
.alert {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
}
|
||||
.alert-success {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b2dba1;
|
||||
}
|
||||
.alert-info {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #9acfea;
|
||||
}
|
||||
.alert-warning {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #f5e79e;
|
||||
}
|
||||
.alert-danger {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dca7a7;
|
||||
}
|
||||
.progress {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.list-group {
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.list-group-item.active,
|
||||
.list-group-item.active:hover,
|
||||
.list-group-item.active:focus {
|
||||
text-shadow: 0 -1px 0 #3071a9;
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3278b3;
|
||||
}
|
||||
.panel {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
}
|
||||
.panel-default > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-primary > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-success > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-info > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-warning > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-danger > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.well {
|
||||
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dcdcdc;
|
||||
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-theme.css.map */
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
5785
MVCTemplate/MVCtemplateWithBasicLogin/css/bootstrap.css
vendored
5785
MVCTemplate/MVCtemplateWithBasicLogin/css/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,38 +0,0 @@
|
||||
#title {
|
||||
margin-top: 12px;
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
|
||||
}
|
||||
#menu {
|
||||
border-top: solid 6px #000;
|
||||
background-color: #fff
|
||||
color: #fff;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#menu a {
|
||||
background-color: #f00;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
#menu a:hover {
|
||||
background-color: #f00;
|
||||
color: #ddd;
|
||||
text-decoration:underline;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#content {
|
||||
background-color: #fff;
|
||||
border-top: solid 6px #f00;
|
||||
|
||||
}
|
||||
|
||||
#footer {
|
||||
margin_top: 20px;
|
||||
text-align: center;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
}
|
||||
Binary file not shown.
@@ -1,229 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||
<missing-glyph horiz-adv-x="500" />
|
||||
<glyph />
|
||||
<glyph />
|
||||
<glyph unicode="
" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
|
||||
<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="434" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="163" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="72" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
|
||||
<glyph unicode="−" d="M200 400h900v300h-900v-300z" />
|
||||
<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
|
||||
<glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
|
||||
<glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
|
||||
<glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
|
||||
<glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
|
||||
<glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
|
||||
<glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
|
||||
<glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
|
||||
<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
|
||||
<glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
|
||||
<glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
|
||||
<glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
|
||||
<glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
|
||||
<glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
|
||||
<glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
|
||||
<glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
|
||||
<glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
|
||||
<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
|
||||
<glyph unicode="" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
|
||||
<glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
|
||||
<glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
|
||||
<glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
|
||||
<glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
|
||||
<glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
|
||||
<glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
|
||||
<glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
|
||||
<glyph unicode="" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
|
||||
<glyph unicode="" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
|
||||
<glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
|
||||
<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
|
||||
<glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
|
||||
<glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
|
||||
<glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
|
||||
<glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
|
||||
<glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
|
||||
<glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
|
||||
<glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
|
||||
<glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
|
||||
<glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
|
||||
<glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
|
||||
<glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
|
||||
<glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
|
||||
<glyph unicode="" d="M200 0l900 550l-900 550v-1100z" />
|
||||
<glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
|
||||
<glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
|
||||
<glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
|
||||
<glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
|
||||
<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
|
||||
<glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z" />
|
||||
<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
|
||||
<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
|
||||
<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" />
|
||||
<glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
|
||||
<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
|
||||
<glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
|
||||
<glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
|
||||
<glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
|
||||
<glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
|
||||
<glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
|
||||
<glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
|
||||
<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
|
||||
<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
|
||||
<glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
|
||||
<glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
|
||||
<glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
|
||||
<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
|
||||
<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
|
||||
<glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
|
||||
<glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
|
||||
<glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
|
||||
<glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
|
||||
<glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
|
||||
<glyph unicode="" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
|
||||
<glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
|
||||
<glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
|
||||
<glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
|
||||
<glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
|
||||
<glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
|
||||
<glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
|
||||
<glyph unicode="" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
|
||||
<glyph unicode="" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
|
||||
<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
|
||||
<glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
|
||||
<glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
|
||||
<glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
|
||||
<glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
|
||||
<glyph unicode="" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
|
||||
<glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
|
||||
<glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
|
||||
<glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
|
||||
<glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
|
||||
<glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
|
||||
<glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
|
||||
<glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
|
||||
<glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
|
||||
<glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
|
||||
<glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
Before Width: | Height: | Size: 62 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 3.9 KiB |
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
$view = new stdClass();
|
||||
$view->pageTitle = 'Homepage';
|
||||
|
||||
require_once("logincontroller.php");
|
||||
|
||||
|
||||
|
||||
require_once('Views/index.phtml');
|
||||
1951
MVCTemplate/MVCtemplateWithBasicLogin/js/bootstrap.js
vendored
1951
MVCTemplate/MVCtemplateWithBasicLogin/js/bootstrap.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
var_dump($_SESSION);
|
||||
|
||||
if (isset($_POST["loginbutton"])) {
|
||||
$username = $_POST["username"];
|
||||
$password = $_POST["password"];
|
||||
echo $username;
|
||||
echo $password;
|
||||
|
||||
if ($username == "a" && $password == "b") {
|
||||
// better would be to check these variables against your database
|
||||
|
||||
// SELECT * FROM usertable WHERE username=$username AND password=$password
|
||||
// if number of rows returned > 0 then the username and password matched
|
||||
|
||||
|
||||
echo "You are logged in";
|
||||
$_SESSION["login"] = $username;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "Error in username and password";
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST["logoutbutton"]))
|
||||
{
|
||||
echo "logout user";
|
||||
unset($_SESSION["login"]);
|
||||
session_destroy();
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
$view = new stdClass();
|
||||
$view->pageTitle = 'Page1';
|
||||
//var_dump($_POST);
|
||||
|
||||
require_once("logincontroller.php");
|
||||
|
||||
|
||||
require_once('Views/page1.phtml');
|
||||
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
$view = new stdClass();
|
||||
$view->pageTitle = 'Page2';
|
||||
//var_dump($_POST);
|
||||
|
||||
require_once("logincontroller.php");
|
||||
|
||||
|
||||
require_once('Views/page2.phtml');
|
||||
112
Models/AuthExample.php
Normal file
112
Models/AuthExample.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
/**
|
||||
* Example controller showing how to use the simplified authentication
|
||||
*
|
||||
* This file demonstrates how to use the User::checkAuth() and User::checkAdmin()
|
||||
* methods to protect routes without using middleware.
|
||||
*/
|
||||
|
||||
require_once('Models/User.php');
|
||||
|
||||
/**
|
||||
* Example of a protected endpoint that requires authentication
|
||||
*/
|
||||
function protectedEndpoint() {
|
||||
// Check if user is authenticated
|
||||
$auth = User::checkAuth();
|
||||
if (!$auth) {
|
||||
// The checkAuth method already sent the error response
|
||||
return;
|
||||
}
|
||||
|
||||
// User is authenticated, proceed with the endpoint logic
|
||||
$response = [
|
||||
'status' => 'success',
|
||||
'message' => 'You are authenticated',
|
||||
'user' => [
|
||||
'id' => $auth['uid'],
|
||||
'username' => $auth['username']
|
||||
]
|
||||
];
|
||||
|
||||
// Send response
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example of an admin-only endpoint
|
||||
*/
|
||||
function adminEndpoint() {
|
||||
// Check if user is an admin
|
||||
$auth = User::checkAdmin();
|
||||
if (!$auth) {
|
||||
// The checkAdmin method already sent the error response
|
||||
return;
|
||||
}
|
||||
|
||||
// User is an admin, proceed with the admin-only logic
|
||||
$response = [
|
||||
'status' => 'success',
|
||||
'message' => 'You have admin access',
|
||||
'user' => [
|
||||
'id' => $auth['uid'],
|
||||
'username' => $auth['username']
|
||||
]
|
||||
];
|
||||
|
||||
// Send response
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example of a public endpoint that doesn't require authentication
|
||||
* but can still use authentication data if available
|
||||
*/
|
||||
function publicEndpoint() {
|
||||
// Check if user is authenticated, but don't require it
|
||||
$auth = User::checkAuth(false);
|
||||
|
||||
$response = [
|
||||
'status' => 'success',
|
||||
'message' => 'This is a public endpoint'
|
||||
];
|
||||
|
||||
// Add user info if authenticated
|
||||
if ($auth) {
|
||||
$response['user'] = [
|
||||
'id' => $auth['uid'],
|
||||
'username' => $auth['username']
|
||||
];
|
||||
} else {
|
||||
$response['user'] = 'Guest';
|
||||
}
|
||||
|
||||
// Send response
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example of how to use these functions in a simple router
|
||||
*/
|
||||
function handleRequest() {
|
||||
$route = $_GET['route'] ?? 'public';
|
||||
|
||||
switch ($route) {
|
||||
case 'protected':
|
||||
protectedEndpoint();
|
||||
break;
|
||||
case 'admin':
|
||||
adminEndpoint();
|
||||
break;
|
||||
case 'public':
|
||||
default:
|
||||
publicEndpoint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Call the router function
|
||||
handleRequest();
|
||||
199
Models/AuthService.php
Normal file
199
Models/AuthService.php
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
require_once('UserDataSet.php');
|
||||
|
||||
/**
|
||||
* Authentication service for handling JWT-based authentication
|
||||
*/
|
||||
class AuthService {
|
||||
private string $secretKey;
|
||||
private int $tokenExpiry;
|
||||
|
||||
/**
|
||||
* Initialises the authentication service
|
||||
* Loads configuration from environment variables
|
||||
* @throws Exception if OpenSSL extension is not loaded
|
||||
*/
|
||||
public function __construct() {
|
||||
// Load environment variables from .env file
|
||||
$envFile = __DIR__ . '/../.env';
|
||||
if (file_exists($envFile)) {
|
||||
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($lines as $line) {
|
||||
// Skip comments
|
||||
if (strpos($line, '#') === 0) continue;
|
||||
|
||||
// Parse environment variable
|
||||
list($name, $value) = explode('=', $line, 2);
|
||||
$name = trim($name);
|
||||
$value = trim($value);
|
||||
|
||||
if (!empty($name)) {
|
||||
putenv(sprintf('%s=%s', $name, $value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set configuration from environment variables with defaults
|
||||
$this->secretKey = getenv('JWT_SECRET_KEY') ?: 'your-256-bit-secret';
|
||||
$this->tokenExpiry = (int)(getenv('JWT_TOKEN_EXPIRY') ?: 3600);
|
||||
|
||||
// Verify OpenSSL extension is available
|
||||
if (!extension_loaded('openssl')) {
|
||||
throw new Exception('OpenSSL extension is required for JWT');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a JWT token for a user
|
||||
* @param array $userData User information to include in token
|
||||
* @return string The generated JWT token
|
||||
*/
|
||||
public function generateToken(array $userData): string {
|
||||
$issuedAt = time();
|
||||
$expire = $issuedAt + $this->tokenExpiry;
|
||||
|
||||
$payload = [
|
||||
'iat' => $issuedAt,
|
||||
'exp' => $expire,
|
||||
'uid' => $userData['id'],
|
||||
'username' => $userData['username'],
|
||||
'accessLevel' => $userData['userType']
|
||||
];
|
||||
|
||||
return $this->encodeJWT($payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a JWT token
|
||||
* @param string $token The JWT token to validate
|
||||
* @return array|null The decoded payload if valid, null otherwise
|
||||
*/
|
||||
public function validateToken(string $token): ?array {
|
||||
try {
|
||||
$payload = $this->decodeJWT($token);
|
||||
|
||||
// Check if token is expired
|
||||
if ($payload === null || !isset($payload['exp']) || $payload['exp'] < time()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $payload;
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes data into a JWT token
|
||||
* @param array $payload The data to encode
|
||||
* @return string The encoded JWT token
|
||||
*/
|
||||
private function encodeJWT(array $payload): string {
|
||||
// Create and encode header
|
||||
$header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
|
||||
$header = $this->base64UrlEncode($header);
|
||||
|
||||
// Create and encode payload
|
||||
$payload = json_encode($payload);
|
||||
$payload = $this->base64UrlEncode($payload);
|
||||
|
||||
// Create and encode signature
|
||||
$signature = hash_hmac('sha256', "$header.$payload", $this->secretKey, true);
|
||||
$signature = $this->base64UrlEncode($signature);
|
||||
|
||||
return "$header.$payload.$signature";
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a JWT token
|
||||
* @param string $token The JWT token to decode
|
||||
* @return array|null The decoded payload if valid, null otherwise
|
||||
*/
|
||||
private function decodeJWT(string $token): ?array {
|
||||
// Split token into components
|
||||
$parts = explode('.', $token);
|
||||
if (count($parts) !== 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
[$header, $payload, $signature] = $parts;
|
||||
|
||||
// Verify signature
|
||||
$validSignature = $this->base64UrlEncode(
|
||||
hash_hmac('sha256', "$header.$payload", $this->secretKey, true)
|
||||
);
|
||||
|
||||
if ($signature !== $validSignature) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Decode and return payload
|
||||
return json_decode($this->base64UrlDecode($payload), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes data using base64url encoding
|
||||
* @param string $data The data to encode
|
||||
* @return string The encoded data
|
||||
*/
|
||||
private function base64UrlEncode(string $data): string {
|
||||
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes base64url encoded data
|
||||
* @param string $data The data to decode
|
||||
* @return string The decoded data
|
||||
*/
|
||||
private function base64UrlDecode(string $data): string {
|
||||
return base64_decode(strtr($data, '-_', '+/') . str_repeat('=', 3 - (3 + strlen($data)) % 4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a refresh token for a user
|
||||
* @param array $userData User information to include in token
|
||||
* @return string The generated refresh token
|
||||
*/
|
||||
public function generateRefreshToken(array $userData): string {
|
||||
$issuedAt = time();
|
||||
$expire = $issuedAt + ($this->tokenExpiry * 24); // Refresh token lasts 24 times longer than access token
|
||||
|
||||
$payload = [
|
||||
'iat' => $issuedAt,
|
||||
'exp' => $expire,
|
||||
'uid' => $userData['id'],
|
||||
'username' => $userData['username'],
|
||||
'type' => 'refresh'
|
||||
];
|
||||
|
||||
return $this->encodeJWT($payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes an access token using a refresh token
|
||||
* @param string $refreshToken The refresh token
|
||||
* @return string|null The new access token if valid, null otherwise
|
||||
*/
|
||||
public function refreshToken(string $refreshToken): ?string {
|
||||
try {
|
||||
$payload = $this->decodeJWT($refreshToken);
|
||||
|
||||
// Check if token is expired or not a refresh token
|
||||
if ($payload === null || !isset($payload['exp']) || $payload['exp'] < time() ||
|
||||
!isset($payload['type']) || $payload['type'] !== 'refresh') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Generate a new access token
|
||||
$userData = [
|
||||
'id' => $payload['uid'],
|
||||
'username' => $payload['username'],
|
||||
'userType' => isset($payload['accessLevel']) ? $payload['accessLevel'] : 0
|
||||
];
|
||||
|
||||
return $this->generateToken($userData);
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
Models/Database.php
Normal file → Executable file
43
Models/Database.php
Normal file → Executable file
@@ -1,18 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* Database connection handler using Singleton pattern
|
||||
*/
|
||||
class Database {
|
||||
/**
|
||||
* @var Database
|
||||
* @var Database|null The singleton instance
|
||||
*/
|
||||
protected static $_dbInstance = null;
|
||||
|
||||
/**
|
||||
* @var PDO
|
||||
* @var PDO The database connection handle
|
||||
*/
|
||||
protected $_dbHandle;
|
||||
|
||||
/**
|
||||
* Gets the database connection handle
|
||||
* @return PDO The database connection
|
||||
*/
|
||||
public function getDbConnection(): PDO
|
||||
{
|
||||
return $this->_dbHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the singleton instance of the Database class
|
||||
* @return Database The database instance
|
||||
*/
|
||||
public static function getInstance(): ?Database
|
||||
{
|
||||
if(self::$_dbInstance == null) {
|
||||
@@ -21,15 +34,37 @@ class Database {
|
||||
return self::$_dbInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to prevent direct instantiation
|
||||
* Initialises the database connection
|
||||
* @throws PDOException if connection fails
|
||||
*/
|
||||
private function __construct() {
|
||||
try {
|
||||
// Create PDO connection with error handling
|
||||
$this->_dbHandle = new PDO("sqlite:Databases/ecobuddy.sqlite");
|
||||
|
||||
// Configure PDO for better error handling and performance
|
||||
$this->_dbHandle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
|
||||
$this->_dbHandle->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
||||
|
||||
// SQLite3 sometimes just forgets foreign keys exist i guess (https://stackoverflow.com/questions/15301643/sqlite3-forgets-to-use-foreign-keys)
|
||||
$this->_dbHandle->exec('PRAGMA foreign_keys = ON;');
|
||||
|
||||
// Set transaction timeout to 5 seconds, just stops the app from hanging when the db is busy
|
||||
$this->_dbHandle->exec('PRAGMA busy_timeout = 5000;');
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
// Log the error and rethrow
|
||||
error_log("Database connection error: " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor to clean up database connection
|
||||
*/
|
||||
public function __destruct() {
|
||||
$this->_dbHandle = null; // destroys the PDO handle when no longer needed
|
||||
$this->_dbHandle = null;
|
||||
}
|
||||
}
|
||||
169
Models/FacilityData.php
Normal file → Executable file
169
Models/FacilityData.php
Normal file → Executable file
@@ -1,11 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* Represents a facility in the EcoBuddy system
|
||||
*
|
||||
* This class serves as a data model for facilities, encapsulating all
|
||||
* the properties and behaviours of a single facility. It follows the
|
||||
* Data Transfer Object (DTO) pattern that I learned about in my
|
||||
* software architecture module.
|
||||
*
|
||||
* Each facility has location data, descriptive information, and metadata
|
||||
* about who contributed it. This class provides a clean interface for
|
||||
* accessing this data throughout the application.
|
||||
*/
|
||||
class FacilityData {
|
||||
protected $_id, $_title, $_category, $_description, $_houseNumber, $_streetName, $_county, $_town, $_postcode, $_lng, $_lat;
|
||||
/**
|
||||
* Facility properties
|
||||
*
|
||||
* @var int $_id - Unique identifier for the facility
|
||||
* @var string $_title - Name of the facility
|
||||
* @var string $_category - Category/type of the facility
|
||||
* @var string $_status - Current status of the facility
|
||||
* @var string $_description - Detailed description of the facility
|
||||
* @var string $_houseNumber - Building number or name
|
||||
* @var string $_streetName - Street name
|
||||
* @var string $_county - County
|
||||
* @var string $_town - Town or city
|
||||
* @var string $_postcode - Postal code
|
||||
* @var float $_lng - Longitude coordinate
|
||||
* @var float $_lat - Latitude coordinate
|
||||
* @var string $_contributor - Username of the person who added the facility
|
||||
*/
|
||||
protected $_id;
|
||||
protected $_title;
|
||||
protected $_category;
|
||||
protected $_status;
|
||||
protected $_description;
|
||||
protected $_houseNumber;
|
||||
protected $_streetName;
|
||||
protected $_county;
|
||||
protected $_town;
|
||||
protected $_postcode;
|
||||
protected $_lng;
|
||||
protected $_lat;
|
||||
protected $_contributor;
|
||||
|
||||
/**
|
||||
* Initialises a new facility with data from the database
|
||||
* @param array $dbRow Database row containing facility data
|
||||
*/
|
||||
public function __construct($dbRow) {
|
||||
$this->_id = $dbRow['_id'];
|
||||
$this->_id = $dbRow['id'];
|
||||
$this->_title = $dbRow['title'];
|
||||
$this->_category = $dbRow['category'];
|
||||
$this->_status = $dbRow['status'];
|
||||
$this->_description = $dbRow['description'];
|
||||
$this->_houseNumber = $dbRow['houseNumber'];
|
||||
$this->_streetName = $dbRow['streetName'];
|
||||
@@ -14,39 +60,158 @@ class FacilityData {
|
||||
$this->_postcode = $dbRow['postcode'];
|
||||
$this->_lng = $dbRow['lng'];
|
||||
$this->_lat = $dbRow['lat'];
|
||||
$this->_contributor = $dbRow['contributor'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's unique identifier
|
||||
*
|
||||
* This ID is used throughout the application to reference this specific
|
||||
* facility, particularly in database operations and API requests.
|
||||
*
|
||||
* @return int The facility ID
|
||||
*/
|
||||
public function getId() {
|
||||
return $this->_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's title
|
||||
*
|
||||
* The title is the primary name or label for the facility that
|
||||
* is displayed to users in the interface.
|
||||
*
|
||||
* @return string The facility title
|
||||
*/
|
||||
public function getTitle() {
|
||||
return $this->_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's category
|
||||
*
|
||||
* The category helps classify facilities by type, such as
|
||||
* recycling centre, community garden, etc.
|
||||
*
|
||||
* @return string The facility category
|
||||
*/
|
||||
public function getCategory() {
|
||||
return $this->_category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's current status
|
||||
*
|
||||
* The status indicates whether the facility is operational,
|
||||
* under maintenance, closed, etc.
|
||||
*
|
||||
* @return string The facility status
|
||||
*/
|
||||
public function getStatus() {
|
||||
return $this->_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's description
|
||||
*
|
||||
* The description provides detailed information about the facility,
|
||||
* its purpose, services offered, etc.
|
||||
*
|
||||
* @return string The facility description
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->_description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's house/building number
|
||||
*
|
||||
* This is part of the facility's address and helps locate it physically.
|
||||
*
|
||||
* @return string The house/building number
|
||||
*/
|
||||
public function getHouseNumber() {
|
||||
return $this->_houseNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's street name
|
||||
*
|
||||
* This is part of the facility's address and helps locate it physically.
|
||||
*
|
||||
* @return string The street name
|
||||
*/
|
||||
public function getStreetName() {
|
||||
return $this->_streetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's county
|
||||
*
|
||||
* This is part of the facility's address and helps locate it physically.
|
||||
*
|
||||
* @return string The county
|
||||
*/
|
||||
public function getCounty() {
|
||||
return $this->_county;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's town or city
|
||||
*
|
||||
* This is part of the facility's address and helps locate it physically.
|
||||
*
|
||||
* @return string The town or city
|
||||
*/
|
||||
public function getTown() {
|
||||
return $this->_town;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's postcode
|
||||
*
|
||||
* This is part of the facility's address and helps locate it physically.
|
||||
* It's also useful for searching facilities by location.
|
||||
*
|
||||
* @return string The postcode
|
||||
*/
|
||||
public function getPostcode() {
|
||||
return $this->_postcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's longitude coordinate
|
||||
*
|
||||
* This is used for displaying the facility on a map and
|
||||
* for calculating distances between facilities.
|
||||
*
|
||||
* @return float The longitude coordinate
|
||||
*/
|
||||
public function getLng() {
|
||||
return $this->_lng;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facility's latitude coordinate
|
||||
*
|
||||
* This is used for displaying the facility on a map and
|
||||
* for calculating distances between facilities.
|
||||
*
|
||||
* @return float The latitude coordinate
|
||||
*/
|
||||
public function getLat() {
|
||||
return $this->_lat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username of the facility's contributor
|
||||
*
|
||||
* This tracks who added the facility to the system,
|
||||
* which is useful for auditing and attribution.
|
||||
*
|
||||
* @return string The contributor's username
|
||||
*/
|
||||
public function getContributor() {
|
||||
return $this->_contributor;
|
||||
}
|
||||
}
|
||||
456
Models/FacilityDataSet.php
Normal file → Executable file
456
Models/FacilityDataSet.php
Normal file → Executable file
@@ -2,29 +2,461 @@
|
||||
require_once ('Database.php');
|
||||
require_once ('FacilityData.php');
|
||||
|
||||
class FacilityDataSet {
|
||||
class FacilityDataSet
|
||||
{
|
||||
protected $_dbHandle, $_dbInstance;
|
||||
|
||||
public function __construct() {
|
||||
public function __construct()
|
||||
{
|
||||
$this->_dbInstance = Database::getInstance();
|
||||
$this->_dbHandle = $this->_dbInstance->getDbConnection();
|
||||
}
|
||||
|
||||
public function fetchAll(): array
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
* Deletes Facility Records being passed a facility id.
|
||||
*/
|
||||
public function deleteFacility($id): bool
|
||||
{
|
||||
$sqlQuery = 'SELECT * FROM ecoFacilities;';
|
||||
try {
|
||||
// Start transaction
|
||||
$this->_dbHandle->beginTransaction();
|
||||
|
||||
$statement = $this->_dbHandle->prepare($sqlQuery); // prepare a PDO statement
|
||||
$statement->execute(); // execute the PDO statemen
|
||||
// Delete related status records first
|
||||
$statusQuery = "DELETE FROM ecoFacilityStatus WHERE facilityid = :id;";
|
||||
$statusStmt = $this->_dbHandle->prepare($statusQuery);
|
||||
$statusStmt->bindValue(':id', (int)$id, \PDO::PARAM_INT);
|
||||
$statusStmt->execute();
|
||||
|
||||
$dataSet = [];
|
||||
// loop through and read the results of the query and cast
|
||||
// them into a matching object
|
||||
while ($row = $statement->fetch()) {
|
||||
$dataSet[] = new FacilityData($row);
|
||||
// Delete the facility
|
||||
$facilityQuery = "DELETE FROM ecoFacilities WHERE id = :id;";
|
||||
$facilityStmt = $this->_dbHandle->prepare($facilityQuery);
|
||||
$facilityStmt->bindValue(':id', (int)$id, \PDO::PARAM_INT);
|
||||
$facilityStmt->execute();
|
||||
|
||||
// Commit transaction
|
||||
$this->_dbHandle->commit();
|
||||
return $facilityStmt->rowCount() > 0;
|
||||
} catch (PDOException $e) {
|
||||
// Rollback on error
|
||||
$this->_dbHandle->rollBack();
|
||||
error_log("Error deleting facility: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
return $dataSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|false Returns array of facilities or false on error
|
||||
* Fetch all facility records with related data
|
||||
*/
|
||||
public function fetchAll(): array|false
|
||||
{
|
||||
try {
|
||||
error_log('Starting fetchAll...');
|
||||
|
||||
$query = "
|
||||
SELECT DISTINCT ecoFacilities.id,
|
||||
ecoFacilities.title,
|
||||
COALESCE(GROUP_CONCAT(ecoFacilityStatus.statusComment, '; '), '') AS status,
|
||||
ecoCategories.name AS category,
|
||||
ecoFacilities.description,
|
||||
ecoFacilities.houseNumber,
|
||||
ecoFacilities.streetName,
|
||||
ecoFacilities.county,
|
||||
ecoFacilities.town,
|
||||
ecoFacilities.postcode,
|
||||
ecoFacilities.lng,
|
||||
ecoFacilities.lat,
|
||||
COALESCE(ecoUser.username, 'Unknown') AS contributor
|
||||
FROM ecoFacilities
|
||||
LEFT JOIN ecoCategories ON ecoCategories.id = ecoFacilities.category
|
||||
LEFT JOIN ecoUser ON ecoUser.id = ecoFacilities.contributor
|
||||
LEFT JOIN ecoFacilityStatus ON ecoFacilityStatus.facilityid = ecoFacilities.id
|
||||
GROUP BY ecoFacilities.id, ecoFacilities.title, ecoCategories.name,
|
||||
ecoFacilities.description, ecoFacilities.streetName,
|
||||
ecoFacilities.county, ecoFacilities.town, ecoFacilities.postcode,
|
||||
ecoUser.username
|
||||
ORDER BY ecoFacilities.id ASC;
|
||||
";
|
||||
|
||||
error_log('Preparing query...');
|
||||
$dataStmt = $this->_dbHandle->prepare($query);
|
||||
|
||||
error_log('Executing query...');
|
||||
$dataStmt->execute();
|
||||
|
||||
error_log('Fetching results...');
|
||||
$results = $dataStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($results === false) {
|
||||
error_log('Query returned false');
|
||||
return false;
|
||||
}
|
||||
|
||||
error_log('Query successful. Row count: ' . count($results));
|
||||
return $results;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log("Database error in fetchAll: " . $e->getMessage());
|
||||
error_log("SQL State: " . $e->getCode());
|
||||
error_log("Stack trace: " . $e->getTraceAsString());
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
error_log("General error in fetchAll: " . $e->getMessage());
|
||||
error_log("Stack trace: " . $e->getTraceAsString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new facility in the database
|
||||
* @param array $data Facility data
|
||||
* @return array|false The created facility data or false on failure
|
||||
*/
|
||||
public function createFacility($data)
|
||||
{
|
||||
try {
|
||||
$this->_dbHandle->beginTransaction();
|
||||
|
||||
// Validate coordinates
|
||||
if (!is_numeric($data['lng']) || !is_numeric($data['lat']) ||
|
||||
$data['lng'] < -180 || $data['lng'] > 180 ||
|
||||
$data['lat'] < -90 || $data['lat'] > 90) {
|
||||
throw new Exception('Invalid coordinates provided');
|
||||
}
|
||||
|
||||
// Get contributor ID
|
||||
$contributorId = $this->getContributorId($data['contributor']);
|
||||
if (!$contributorId) {
|
||||
throw new Exception('Invalid contributor name');
|
||||
}
|
||||
|
||||
// Get category ID
|
||||
$categoryId = $this->getCategoryId($data['category']);
|
||||
if (!$categoryId) {
|
||||
// If category doesn't exist, create it
|
||||
$categoryId = $this->createCategory($data['category']);
|
||||
if (!$categoryId) {
|
||||
throw new Exception('Failed to create category: ' . $data['category']);
|
||||
}
|
||||
}
|
||||
|
||||
// Insert facility
|
||||
$sql = "INSERT INTO ecoFacilities (title, category, description, houseNumber,
|
||||
streetName, county, town, postcode, lng, lat, contributor)
|
||||
VALUES (:title, :category, :description, :houseNumber,
|
||||
:streetName, :county, :town, :postcode, :longitude, :latitude, :contributor)";
|
||||
|
||||
$stmt = $this->_dbHandle->prepare($sql);
|
||||
$params = [
|
||||
':title' => $data['title'],
|
||||
':category' => $categoryId,
|
||||
':description' => $data['description'],
|
||||
':houseNumber' => $data['houseNumber'],
|
||||
':streetName' => $data['streetName'],
|
||||
':county' => $data['county'],
|
||||
':town' => $data['town'],
|
||||
':postcode' => $data['postcode'],
|
||||
':longitude' => $data['lng'],
|
||||
':latitude' => $data['lat'],
|
||||
':contributor' => $contributorId
|
||||
];
|
||||
|
||||
error_log("Executing SQL with params: " . print_r($params, true));
|
||||
|
||||
if (!$stmt->execute($params)) {
|
||||
throw new Exception('Failed to insert facility: ' . implode(', ', $stmt->errorInfo()));
|
||||
}
|
||||
|
||||
$facilityId = $this->_dbHandle->lastInsertId();
|
||||
$this->_dbHandle->commit();
|
||||
|
||||
// Return the created facility
|
||||
return $this->getFacilityById($facilityId);
|
||||
} catch (Exception $e) {
|
||||
$this->_dbHandle->rollBack();
|
||||
error_log("Error in createFacility: " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function createCategory($categoryName)
|
||||
{
|
||||
try {
|
||||
$sql = "INSERT INTO ecoCategories (name) VALUES (:name)";
|
||||
$stmt = $this->_dbHandle->prepare($sql);
|
||||
$stmt->execute([':name' => $categoryName]);
|
||||
return $this->_dbHandle->lastInsertId();
|
||||
} catch (Exception $e) {
|
||||
error_log("Error creating category: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing facility in the database
|
||||
* @param int $id Facility ID
|
||||
* @param array $data Updated facility data
|
||||
* @return array|false The updated facility data or false on failure
|
||||
*/
|
||||
public function updateFacility($id, $data) {
|
||||
try {
|
||||
// Start transaction
|
||||
$this->_dbHandle->beginTransaction();
|
||||
|
||||
// Validate coordinates
|
||||
if (!is_numeric($data['lng']) || !is_numeric($data['lat']) ||
|
||||
$data['lng'] < -180 || $data['lng'] > 180 ||
|
||||
$data['lat'] < -90 || $data['lat'] > 90) {
|
||||
throw new Exception('Invalid coordinates');
|
||||
}
|
||||
|
||||
// Get Contributor ID
|
||||
$query = "SELECT ecoUser.id FROM ecoUser WHERE ecoUser.username = :contributor;";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
$stmt->bindValue(':contributor', $data['contributor']);
|
||||
$stmt->execute();
|
||||
$contributorResult = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$contributorResult) {
|
||||
throw new Exception('Invalid contributor username');
|
||||
}
|
||||
$contributorId = $contributorResult['id'];
|
||||
|
||||
// Get Category ID
|
||||
$query = "SELECT ecoCategories.id FROM ecoCategories WHERE ecoCategories.name = :category;";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
$stmt->bindValue(':category', $data['category']);
|
||||
$stmt->execute();
|
||||
$categoryResult = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$categoryResult) {
|
||||
throw new Exception('Invalid category name');
|
||||
}
|
||||
$categoryId = $categoryResult['id'];
|
||||
|
||||
// Update facility
|
||||
$query = "
|
||||
UPDATE ecoFacilities
|
||||
SET title = :title,
|
||||
category = :category,
|
||||
description = :description,
|
||||
houseNumber = :houseNumber,
|
||||
streetName = :streetName,
|
||||
county = :county,
|
||||
town = :town,
|
||||
postcode = :postcode,
|
||||
lng = :lng,
|
||||
lat = :lat,
|
||||
contributor = :contributor
|
||||
WHERE id = :id
|
||||
";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
$params = [
|
||||
':title' => $data['title'],
|
||||
':category' => $categoryId,
|
||||
':description' => $data['description'],
|
||||
':houseNumber' => $data['houseNumber'],
|
||||
':streetName' => $data['streetName'],
|
||||
':county' => $data['county'],
|
||||
':town' => $data['town'],
|
||||
':postcode' => $data['postcode'],
|
||||
':lng' => $data['lng'],
|
||||
':lat' => $data['lat'],
|
||||
':contributor' => $contributorId,
|
||||
':id' => $id
|
||||
];
|
||||
|
||||
error_log("Executing update query with params: " . print_r($params, true));
|
||||
|
||||
if (!$stmt->execute($params)) {
|
||||
throw new Exception('Failed to update facility: ' . implode(', ', $stmt->errorInfo()));
|
||||
}
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$this->_dbHandle->commit();
|
||||
return $this->getFacilityById($id);
|
||||
}
|
||||
|
||||
$this->_dbHandle->rollBack();
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
$this->_dbHandle->rollBack();
|
||||
error_log("Error updating facility: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a facility by its ID
|
||||
* @param int $id Facility ID
|
||||
* @return array|false The facility data or false if not found
|
||||
*/
|
||||
public function getFacilityById($id) {
|
||||
try {
|
||||
$query = "
|
||||
SELECT DISTINCT ecoFacilities.id,
|
||||
ecoFacilities.title,
|
||||
COALESCE(GROUP_CONCAT(ecoFacilityStatus.statusComment, ';'), '') AS status,
|
||||
ecoCategories.name AS category,
|
||||
ecoFacilities.description,
|
||||
ecoFacilities.houseNumber,
|
||||
ecoFacilities.streetName,
|
||||
ecoFacilities.county,
|
||||
ecoFacilities.town,
|
||||
ecoFacilities.postcode,
|
||||
ecoFacilities.lng,
|
||||
ecoFacilities.lat,
|
||||
COALESCE(ecoUser.username, 'Unknown') AS contributor
|
||||
FROM ecoFacilities
|
||||
LEFT JOIN ecoCategories ON ecoCategories.id = ecoFacilities.category
|
||||
LEFT JOIN ecoUser ON ecoUser.id = ecoFacilities.contributor
|
||||
LEFT JOIN ecoFacilityStatus ON ecoFacilityStatus.facilityid = ecoFacilities.id
|
||||
WHERE ecoFacilities.id = ?
|
||||
GROUP BY ecoFacilities.id, ecoFacilities.title, ecoCategories.name,
|
||||
ecoFacilities.description, ecoFacilities.streetName,
|
||||
ecoFacilities.county, ecoFacilities.town, ecoFacilities.postcode,
|
||||
ecoUser.username;
|
||||
";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
$stmt->execute([$id]);
|
||||
return $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error getting facility: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function getContributorId($username)
|
||||
{
|
||||
try {
|
||||
$query = "SELECT ecoUser.id FROM ecoUser WHERE ecoUser.username = :username;";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
$stmt->bindValue(':username', $username);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $result ? $result['id'] : false;
|
||||
} catch (Exception $e) {
|
||||
error_log("Error getting contributor ID: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function getCategoryId($categoryName)
|
||||
{
|
||||
try {
|
||||
$query = "SELECT ecoCategories.id FROM ecoCategories WHERE ecoCategories.name = :name;";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
$stmt->bindValue(':name', $categoryName);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $result ? $result['id'] : false;
|
||||
} catch (Exception $e) {
|
||||
error_log("Error getting category ID: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new status comment to a facility
|
||||
* @param int $facilityId The ID of the facility
|
||||
* @param string $statusComment The status comment to add
|
||||
* @return bool True if successful, false otherwise
|
||||
*/
|
||||
public function addFacilityStatus($facilityId, $statusComment)
|
||||
{
|
||||
try {
|
||||
// Log input parameters
|
||||
error_log("Adding facility status - Facility ID: " . $facilityId . ", Comment: " . $statusComment);
|
||||
|
||||
// Start transaction
|
||||
$this->_dbHandle->beginTransaction();
|
||||
|
||||
// Insert new status comment
|
||||
$query = "INSERT INTO ecoFacilityStatus (facilityId, statusComment) VALUES (:facilityId, :statusComment)";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
|
||||
// Log the prepared statement
|
||||
error_log("Prepared statement: " . $query);
|
||||
|
||||
// Bind values and log them
|
||||
$stmt->bindValue(':facilityId', (int)$facilityId, PDO::PARAM_INT);
|
||||
$stmt->bindValue(':statusComment', $statusComment);
|
||||
error_log("Bound values - Facility ID: " . (int)$facilityId . ", Comment: " . $statusComment);
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
$errorInfo = $stmt->errorInfo();
|
||||
error_log("SQL Error: " . print_r($errorInfo, true));
|
||||
throw new Exception('Failed to insert status comment: ' . implode(', ', $errorInfo));
|
||||
}
|
||||
|
||||
$this->_dbHandle->commit();
|
||||
error_log("Successfully added facility status");
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
$this->_dbHandle->rollBack();
|
||||
error_log("Error adding facility status: " . $e->getMessage());
|
||||
error_log("Stack trace: " . $e->getTraceAsString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all status comments for a facility
|
||||
* @param int $facilityId The ID of the facility
|
||||
* @return array Array of status comments with their IDs
|
||||
*/
|
||||
public function getFacilityStatuses($facilityId)
|
||||
{
|
||||
try {
|
||||
$query = "SELECT id, statusComment FROM ecoFacilityStatus WHERE facilityId = :facilityId ORDER BY id DESC";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
$stmt->bindValue(':facilityId', (int)$facilityId, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (Exception $e) {
|
||||
error_log("Error getting facility statuses: " . $e->getMessage());
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing status comment
|
||||
* @param int $statusId The ID of the status comment
|
||||
* @param string $statusComment The updated status comment
|
||||
* @return bool True if successful, false otherwise
|
||||
*/
|
||||
public function updateFacilityStatus($statusId, $statusComment)
|
||||
{
|
||||
try {
|
||||
$query = "UPDATE ecoFacilityStatus SET statusComment = :statusComment WHERE id = :statusId";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
$stmt->bindValue(':statusId', (int)$statusId, PDO::PARAM_INT);
|
||||
$stmt->bindValue(':statusComment', $statusComment);
|
||||
return $stmt->execute();
|
||||
} catch (Exception $e) {
|
||||
error_log("Error updating facility status: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a specific status comment
|
||||
* @param int $statusId The ID of the status comment to delete
|
||||
* @return bool True if successful, false otherwise
|
||||
*/
|
||||
public function deleteFacilityStatus($statusId)
|
||||
{
|
||||
try {
|
||||
$query = "DELETE FROM ecoFacilityStatus WHERE id = :statusId";
|
||||
$stmt = $this->_dbHandle->prepare($query);
|
||||
$stmt->bindValue(':statusId', (int)$statusId, PDO::PARAM_INT);
|
||||
return $stmt->execute();
|
||||
} catch (Exception $e) {
|
||||
error_log("Error deleting facility status: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
56
Models/Paginator.php
Normal file → Executable file
56
Models/Paginator.php
Normal file → Executable file
@@ -1 +1,57 @@
|
||||
<?php
|
||||
require_once('FacilityDataSet.php');
|
||||
class Paginator {
|
||||
protected $_pages, $_totalPages, $_rowLimit, $_pageMatrix, $_rowCount;
|
||||
|
||||
public function __construct($rowLimit, $dataset) {
|
||||
$this->_rowLimit = $rowLimit;
|
||||
$this->_totalPages = $this->calculateTotalPages($dataset['count']);
|
||||
$this->_rowCount = $dataset['count'];
|
||||
$this->_pages = $dataset['dataset'];
|
||||
$this->_pageMatrix = $this->Paginate();
|
||||
}
|
||||
public function getTotalPages() {
|
||||
return $this->_totalPages;
|
||||
}
|
||||
private function calculateTotalPages(int $count): int {
|
||||
return $count > 0 ? ceil($count / $this->_rowLimit) : 0;
|
||||
}
|
||||
|
||||
public function Paginate(): array {
|
||||
$pageMatrix = [];
|
||||
for ($i = 0; $i < $this->_totalPages; $i++) {
|
||||
$page = [];
|
||||
$start = $i * $this->_rowLimit;
|
||||
$end = min($start + $this->_rowLimit, $this->_rowCount); // Ensure within bounds
|
||||
|
||||
for ($j = $start; $j < $end; $j++) {
|
||||
$page[] = $this->_pages[$j];
|
||||
}
|
||||
|
||||
$pageMatrix[$i] = $page;
|
||||
}
|
||||
return $pageMatrix;
|
||||
}
|
||||
|
||||
public function getPageFromUri(): int {
|
||||
// Retrieve 'page' parameter and default to 0 if missing or invalid
|
||||
return filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT, [
|
||||
'options' => ['default' => 0, 'min_range' => 0] // Default to 1 if invalid or missing
|
||||
]);
|
||||
}
|
||||
|
||||
public function getPage(int $pageNumber): array {
|
||||
|
||||
if ($pageNumber < 0 || $pageNumber >= $this->_totalPages) {
|
||||
return []; // Return an empty array if the page number is invalid
|
||||
}
|
||||
return $this->_pageMatrix[$pageNumber];
|
||||
}
|
||||
|
||||
public function countPageResults(int $pageNumber): int {
|
||||
if ($pageNumber < 0 || $pageNumber >= $this->_totalPages) {
|
||||
return 0; // Return 0 if the page number is invalid
|
||||
}
|
||||
return count($this->_pageMatrix[$pageNumber]);
|
||||
}
|
||||
}
|
||||
206
Models/User.php
Normal file → Executable file
206
Models/User.php
Normal file → Executable file
@@ -1,51 +1,133 @@
|
||||
<?php
|
||||
|
||||
require_once('UserDataSet.php');
|
||||
class User {
|
||||
protected $_username, $_loggedIn, $_userId;
|
||||
require_once('AuthService.php');
|
||||
|
||||
/**
|
||||
* User class - Handles user authentication and session management
|
||||
*
|
||||
* This class manages user authentication using JWT tokens and provides
|
||||
* methods for logging in, logging out, and checking user permissions.
|
||||
* I've implemented this based on JWT authentication
|
||||
*/
|
||||
class User {
|
||||
/**
|
||||
* Class properties
|
||||
* @var string $_username - The user's username
|
||||
* @var bool $_loggedIn - Whether the user is currently logged in
|
||||
* @var string $_userId - The user's unique ID
|
||||
* @var int $_accessLevel - The user's access level (admin = 1, regular user = 2)
|
||||
* @var AuthService $_authService - Service for JWT token handling
|
||||
*/
|
||||
protected $_username, $_loggedIn, $_userId, $_accessLevel;
|
||||
protected $_authService;
|
||||
|
||||
/**
|
||||
* Gets the current user's username
|
||||
*
|
||||
* @return string The username of the current user
|
||||
*/
|
||||
public function getUsername() {
|
||||
return $this->_username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current user's ID
|
||||
*
|
||||
* @return string The ID of the current user
|
||||
*/
|
||||
public function getUserId() {
|
||||
return $this->_userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor - Initialises user from JWT token if available
|
||||
*
|
||||
* Checks for a JWT token in the Authorization header and validates it.
|
||||
* If valid, sets user properties based on the token payload.
|
||||
* Also starts a session if needed for CAPTCHA verification during registration.
|
||||
*/
|
||||
public function __construct() {
|
||||
session_start();
|
||||
|
||||
// Initialise default values
|
||||
$this->_username = "None";
|
||||
$this->_loggedIn = false;
|
||||
$this->_userId = "0";
|
||||
|
||||
if(isset($_SESSION['login'])) {
|
||||
$this->_username = $_SESSION['login'];
|
||||
$this->_userId = $_SESSION['uid'];
|
||||
$this->_loggedIn = true;
|
||||
$this->_accessLevel = null;
|
||||
$this->_authService = new AuthService();
|
||||
|
||||
// Check for JWT token in Authorization header
|
||||
$headers = getallheaders();
|
||||
$token = isset($headers['Authorization']) ? str_replace('Bearer ', '', $headers['Authorization']) : null;
|
||||
|
||||
// Validate token if it exists
|
||||
if ($token) {
|
||||
$payload = $this->_authService->validateToken($token);
|
||||
if ($payload) {
|
||||
$this->_username = $payload['username'];
|
||||
$this->_userId = $payload['uid'];
|
||||
$this->_accessLevel = $payload['accessLevel'];
|
||||
$this->_loggedIn = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Start session only if needed for CAPTCHA
|
||||
if (session_status() === PHP_SESSION_NONE && isset($_GET['page']) && $_GET['page'] === 'register') {
|
||||
session_start();
|
||||
}
|
||||
}
|
||||
|
||||
public function init() {
|
||||
$this->_username = "None";
|
||||
$this->_userId = "0";
|
||||
$this->_loggedIn = false;
|
||||
|
||||
if(isset($_SESSION['login'])) {
|
||||
$this->_username = $_SESSION['login'];
|
||||
$this->_userId = $_SESSION['uid'];
|
||||
$this->_loggedIn = true;
|
||||
}
|
||||
/**
|
||||
* Sets the user's access level
|
||||
*
|
||||
* @param int $level The access level to set (admin = 1, regular user = 2)
|
||||
* @return void
|
||||
*/
|
||||
private function setAccessLevel($level) {
|
||||
$this->_accessLevel = $level;
|
||||
}
|
||||
public function Authenticate($username, $password): bool
|
||||
|
||||
/**
|
||||
* Gets the user's access level
|
||||
*
|
||||
* @return int|null The user's access level (admin = 1, regular user = 2) or null if not set
|
||||
*/
|
||||
public function getAccessLevel() {
|
||||
return $this->_accessLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates a user using username and password
|
||||
*
|
||||
* Checks credentials against the database and generates a JWT token if valid.
|
||||
* Sets user properties if authentication is successful.
|
||||
*
|
||||
* @param string $username The username to authenticate
|
||||
* @param string $password The password to verify
|
||||
* @return string|bool JWT token if authentication was successful, false otherwise
|
||||
*/
|
||||
public function Authenticate($username, $password)
|
||||
{
|
||||
$users = new UserDataSet();
|
||||
$userDataSet = $users->checkUserCredentials($username, $password);
|
||||
|
||||
if(count($userDataSet) > 0) {
|
||||
$_SESSION['login'] = $username;
|
||||
$_SESSION['uid'] = $userDataSet[0]->getId();
|
||||
$userData = $userDataSet[0];
|
||||
$accessLevel = $users->checkAccessLevel($username);
|
||||
|
||||
// Generate JWT token
|
||||
$token = $this->_authService->generateToken([
|
||||
'id' => $userData->getId(),
|
||||
'username' => $userData->getUsername(),
|
||||
'userType' => $accessLevel
|
||||
]);
|
||||
|
||||
// Set user properties
|
||||
$this->_loggedIn = true;
|
||||
$this->_username = $username;
|
||||
$this->_userId = $userDataSet[0]->getId();
|
||||
return true;
|
||||
$this->_userId = $userData->getId();
|
||||
$this->_accessLevel = $accessLevel;
|
||||
|
||||
return $token;
|
||||
}
|
||||
else {
|
||||
$this->_loggedIn = false;
|
||||
@@ -53,23 +135,85 @@ class User {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the user out
|
||||
*
|
||||
* Resets all user properties to their default values.
|
||||
* Note: This doesn't invalidate the JWT token - handled client-side
|
||||
* by removing the token from storage.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function logout() {
|
||||
unset($_SESSION['login']);
|
||||
unset($_SESSION['uid']);
|
||||
// Reset user properties
|
||||
$this->_loggedIn = false;
|
||||
$this->_username = "None";
|
||||
$this->_userId = "0";
|
||||
session_destroy();
|
||||
$this->_accessLevel = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user is currently logged in
|
||||
*
|
||||
* @return bool True if the user is logged in, false otherwise
|
||||
*/
|
||||
public function isLoggedIn(): bool
|
||||
{
|
||||
return $this->_loggedIn;
|
||||
}
|
||||
public function __destruct()
|
||||
|
||||
/**
|
||||
* Static method to check if a request is authenticated
|
||||
*
|
||||
* This method can be called from any controller to check if the request
|
||||
* has a valid JWT token. It returns the payload if authenticated or
|
||||
* sends an error response and returns false if not.
|
||||
*
|
||||
* @param bool $required Whether authentication is required (defaults to true)
|
||||
* @return array|false The payload if authenticated, false otherwise
|
||||
*/
|
||||
public static function checkAuth(bool $required = true)
|
||||
{
|
||||
|
||||
$authService = new AuthService();
|
||||
|
||||
// Get the token from the Authorization header
|
||||
$headers = getallheaders();
|
||||
$token = isset($headers['Authorization']) ? str_replace('Bearer ', '', $headers['Authorization']) : null;
|
||||
|
||||
// Validate the token
|
||||
$payload = $token ? $authService->validateToken($token) : null;
|
||||
|
||||
// If authentication is required and no valid token, return error
|
||||
if ($required && !$payload) {
|
||||
header('Content-Type: application/json');
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Authentication required']);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to check if a request is from an admin
|
||||
*
|
||||
* This method can be called from any controller to check if the request
|
||||
* has a valid JWT token with admin access level. It returns the payload
|
||||
* if authenticated as admin or sends an error response and returns false if not.
|
||||
*
|
||||
* @return array|false The payload if authenticated as admin, false otherwise
|
||||
*/
|
||||
public static function checkAdmin()
|
||||
{
|
||||
$payload = self::checkAuth(true);
|
||||
|
||||
if ($payload && isset($payload['accessLevel']) && $payload['accessLevel'] == 1) {
|
||||
return $payload;
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Admin access required']);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
9
Models/UserData.php
Normal file → Executable file
9
Models/UserData.php
Normal file → Executable file
@@ -3,11 +3,10 @@ class UserData {
|
||||
protected $_id, $_username, $_name, $_password, $_usertype;
|
||||
|
||||
public function __construct($dbRow) {
|
||||
$this->_id = $dbRow['_id'];
|
||||
$this->_id = $dbRow['id'];
|
||||
$this->_username = $dbRow['username'];
|
||||
$this->_name = $dbRow['name'];
|
||||
$this->_password = $dbRow['password'];
|
||||
$this->_usertype = $dbRow['usertype'];
|
||||
$this->_usertype = $dbRow['userType'];
|
||||
}
|
||||
|
||||
public function getId() {
|
||||
@@ -18,8 +17,4 @@ class UserData {
|
||||
return $this->_username;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
}
|
||||
40
Models/UserDataSet.php
Normal file → Executable file
40
Models/UserDataSet.php
Normal file → Executable file
@@ -10,26 +10,26 @@ class UserDataSet {
|
||||
$this->_dbHandle = $this->_dbInstance->getDbConnection();
|
||||
}
|
||||
|
||||
public function fetchAll(): array
|
||||
{
|
||||
$sqlQuery = 'SELECT * FROM ecoUser;';
|
||||
|
||||
$statement = $this->_dbHandle->prepare($sqlQuery); // prepare a PDO statement
|
||||
$statement->execute(); // execute the PDO statement
|
||||
|
||||
$dataSet = [];
|
||||
// loop through and read the results of the query and cast
|
||||
// them into a matching object
|
||||
while ($row = $statement->fetch()) {
|
||||
$dataSet[] = new UserData($row);
|
||||
}
|
||||
return $dataSet;
|
||||
/**
|
||||
* @param $username
|
||||
* @return mixed
|
||||
* Query access level of a username, and return their usertype
|
||||
*/
|
||||
public function checkAccessLevel($username) {
|
||||
$sqlQuery = "SELECT ecoUser.userType FROM ecoUser
|
||||
LEFT JOIN ecoUsertypes ON ecoUser.userType = ecoUsertypes.userType
|
||||
WHERE ecoUser.username = ?";
|
||||
$statement = $this->_dbHandle->prepare($sqlQuery);
|
||||
$statement->bindValue(1, $username);
|
||||
$statement->execute();
|
||||
return $statement->fetch(PDO::FETCH_ASSOC)['userType'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $username
|
||||
* @param $password
|
||||
* @return array
|
||||
* Authenticate user with query, and return their details
|
||||
*/
|
||||
public function checkUserCredentials($username, $password): array
|
||||
{
|
||||
@@ -44,16 +44,4 @@ class UserDataSet {
|
||||
}
|
||||
return $dataSet;
|
||||
}
|
||||
public function fetchUser($username): array
|
||||
{
|
||||
$sqlQuery = 'SELECT * FROM ecoUser WHERE username = ?';
|
||||
$statement = $this->_dbHandle->prepare($sqlQuery);
|
||||
$statement->execute([$username]);
|
||||
$dataSet = [];
|
||||
while ($row = $statement->fetch()) {
|
||||
$dataSet[] = new UserData($row);
|
||||
}
|
||||
return $dataSet;
|
||||
}
|
||||
|
||||
}
|
||||
124
Views/index.phtml
Normal file → Executable file
124
Views/index.phtml
Normal file → Executable file
@@ -1,32 +1,104 @@
|
||||
<?php require('template/header.phtml') ?>
|
||||
<?php
|
||||
/**
|
||||
* Main index view for the EcoBuddy application
|
||||
*
|
||||
* This file serves as the main view for the application, displaying
|
||||
* a table of facilities with various actions depending on the user's
|
||||
* access level. It includes modals for creating, updating, deleting,
|
||||
* and viewing statuses of facilities.
|
||||
*
|
||||
* The table is populated dynamically using JavaScript, with the data
|
||||
* stored in sessionStorage.
|
||||
*/
|
||||
require('template/header.phtml')
|
||||
?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-5">
|
||||
<p><?php echo $view->dbMessage; ?></p>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<p>Current script <?php echo $_SERVER["PHP_SELF"]; ?></p>
|
||||
<div class="row">
|
||||
<div class="col-12 p-0" id="facilityContent">
|
||||
<!-- Main content -->
|
||||
<div class="card shadow-sm border-0 rounded-3">
|
||||
<!-- Title and add button (admins only) -->
|
||||
<div class="card-header bg-light py-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="d-flex align-items-center">
|
||||
<h5 class="mb-0 fw-bold text-primary">
|
||||
<i class="bi bi-geo-alt-fill me-2 text-success"></i>Facilities
|
||||
</h5>
|
||||
<!-- Badge showing the number of facilities -->
|
||||
<span class="badge bg-success rounded-pill ms-2" id="facilityCount"></span>
|
||||
</div>
|
||||
<?php if($view->user->getAccessLevel() == 1): ?>
|
||||
<!-- Add new facility button (admin only) -->
|
||||
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#createModal">
|
||||
<i class="bi bi-plus-circle me-1"></i>Add New Facility
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Pagination controls -->
|
||||
<div class="card-footer bg-white py-2">
|
||||
<?php require('template/pagination.phtml');?>
|
||||
</div>
|
||||
<!-- Facilities table -->
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0" id="facilityTable">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<?php if($view->user->getAccessLevel() == 1): ?>
|
||||
<th class="fw-semibold" style="width: 40px;">ID</th>
|
||||
<?php else: ?>
|
||||
<th class="d-none">ID</th>
|
||||
<?php endif; ?>
|
||||
<th class="fw-semibold" style="width: 15%;">Title</th>
|
||||
<th class="fw-semibold text-center" style="width: 10%;">Category</th>
|
||||
<th class="fw-semibold" style="width: 25%;">Description</th>
|
||||
<th class="fw-semibold" style="width: 20%;">Address</th>
|
||||
<th class="fw-semibold text-center" style="width: 8%;" hidden>Postcode</th>
|
||||
<th class="fw-semibold text-center" style="width: 12%;">Coordinates</th>
|
||||
<th class="fw-semibold text-center" style="width: 8%;">Contributor</th>
|
||||
<th class="fw-semibold text-center" style="width: 10%;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="border-top-0">
|
||||
<!-- Table content will be dynamically populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<table class="table table-bordered">
|
||||
<thead> <tr> <th>Facility ID</th> <th>Title</th> <th>Category</th> <th>Description</th> <th>Address</th> <th>Postcode</th> <th>Lat/Long</th> <th>Contributor</th> </tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($view->facilityDataSet as $facilityData) {
|
||||
echo '<tr> <td>' . $facilityData->getId() .
|
||||
'</td> <td>' . $facilityData->getTitle() .
|
||||
'</td> <td>' . $facilityData->getCategory() .
|
||||
'</td> <td>' . $facilityData->getDescription() .
|
||||
'</td> <td>' . $facilityData->getHouseNumber() . " " . $facilityData->getStreetName() . " " . $facilityData->getCounty() . " " . $facilityData->getTown() .
|
||||
'</td> <td>' . $facilityData->getPostcode() .
|
||||
'</td> <td>' . $facilityData->getLatitude() . " " . $facilityData->getLongitude() .
|
||||
'</td> <td>' . $facilityData->getContributor() .
|
||||
'</td> </td> </tr>';
|
||||
} ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- Include modal templates -->
|
||||
<?php require('template/createModal.phtml') ?>
|
||||
<?php require('template/updateModal.phtml') ?>
|
||||
<?php require('template/deleteModal.phtml') ?>
|
||||
<?php require('template/statusModal.phtml') ?>
|
||||
|
||||
<!-- Script to update the facility count badge -->
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Update facility count badge based on data in sessionStorage
|
||||
const updateFacilityCount = () => {
|
||||
const facilityData = JSON.parse(sessionStorage.getItem('facilityData') || '[]');
|
||||
const countBadge = document.getElementById('facilityCount');
|
||||
if (countBadge) {
|
||||
countBadge.textContent = `${facilityData.length} facilities`;
|
||||
}
|
||||
};
|
||||
|
||||
// Initial count update when the page loads
|
||||
updateFacilityCount();
|
||||
|
||||
// Listen for changes in facility data to update the count
|
||||
window.addEventListener('storage', function(e) {
|
||||
if (e.key === 'facilityData') {
|
||||
updateFacilityCount();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php require('template/footer.phtml');?>
|
||||
|
||||
<?php require('template/footer.phtml') ?>
|
||||
145
Views/template/createModal.phtml
Executable file
145
Views/template/createModal.phtml
Executable file
@@ -0,0 +1,145 @@
|
||||
<?php if($view->user->getAccessLevel() == 1): ?>
|
||||
<!-- Create Facility Modal -->
|
||||
<div class="modal fade" id="createModal" tabindex="-1" aria-labelledby="createModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-light">
|
||||
<h5 class="modal-title" id="createModalLabel">
|
||||
<i class="bi bi-plus-circle-fill text-success me-2"></i>Add New Facility
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form id="createForm">
|
||||
<input type="hidden" name="action" value="create">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="titlCreate" class="form-label">Title</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-tag text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="titlCreate" name="titlCreate" placeholder="Enter facility title" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="cateCreate" class="form-label">Category</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-bookmark text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="cateCreate" name="cateCreate" placeholder="Enter facility category" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="descCreate" class="form-label">Description</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-card-text text-success"></i>
|
||||
</span>
|
||||
<textarea class="form-control border-start-0" id="descCreate" name="descCreate" placeholder="Enter facility description" rows="3" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="hnumCreate" class="form-label">House/Building Number</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-house text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="hnumCreate" name="hnumCreate" placeholder="Enter number" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="strtCreate" class="form-label">Street Name</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-signpost text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="strtCreate" name="strtCreate" placeholder="Enter street name" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="townCreate" class="form-label">Town/City</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-building text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="townCreate" name="townCreate" placeholder="Enter town/city" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="cntyCreate" class="form-label">County</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-map text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="cntyCreate" name="cntyCreate" placeholder="Enter county" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="postCreate" class="form-label">Postcode</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-mailbox text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="postCreate" name="postCreate" placeholder="Enter postcode" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="latCreate" class="form-label">Latitude</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-geo-alt text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="latCreate" name="latCreate" placeholder="Enter latitude" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="lngCreate" class="form-label">Longitude</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-geo-alt text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="lngCreate" name="lngCreate" placeholder="Enter longitude" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="contCreate" class="form-label">Contributor</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-person text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0 bg-light" id="contCreate" name="contCreate" placeholder="Auto-filled with your username" disabled required>
|
||||
</div>
|
||||
<small class="text-muted">This will be automatically filled with your username</small>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<div class="w-100 d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="createForm" class="btn btn-success">
|
||||
<i class="bi bi-plus-circle me-1"></i>Create Facility
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
37
Views/template/deleteModal.phtml
Executable file
37
Views/template/deleteModal.phtml
Executable file
@@ -0,0 +1,37 @@
|
||||
<!-- Delete Facility Modal -->
|
||||
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-light">
|
||||
<h5 class="modal-title" id="deleteModalLabel">
|
||||
<i class="bi bi-trash text-danger me-2"></i>Delete Facility
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form id="deleteForm">
|
||||
<input type="hidden" name="action" value="delete">
|
||||
<input type="hidden" name="idDelete" value="">
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<span>Are you sure you want to delete this facility record? This action cannot be undone.</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<p class="mb-1 fw-bold">Facility to be deleted:</p>
|
||||
<p id="deleteConfirmationText" class="text-danger mb-0"></p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<div class="w-100 d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="deleteForm" class="btn btn-danger">
|
||||
<i class="bi bi-trash me-1"></i>Delete Permanently
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
99
Views/template/footer.phtml
Normal file → Executable file
99
Views/template/footer.phtml
Normal file → Executable file
@@ -1,16 +1,99 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div id="footer" class="col-xs-12">
|
||||
<p>George Wilkinson @2024</p>
|
||||
<p>Powered by Bootstrap</p>
|
||||
<div class="site-footer mt-auto">
|
||||
<!-- Footer Content -->
|
||||
<div class="row">
|
||||
<div id="footer" class="col-xs-12">
|
||||
<p class="m-0">George Wilkinson @2024</p>
|
||||
<p class="m-0">Powered by Bootstrap</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap core JavaScript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Application JavaScript -->
|
||||
<!-- Note: simpleAuth.js is already included in the header -->
|
||||
<!-- Note: facilityData.js is already included in the header -->
|
||||
<script src="/public/js/comments.js"></script>
|
||||
|
||||
<!-- Initialize components -->
|
||||
<script>
|
||||
// Only run initialization if not already done
|
||||
if (!window.initializationComplete) {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize auth service
|
||||
const loginButton = document.querySelector('[data-bs-toggle="modal"]');
|
||||
const loginModal = document.getElementById('loginModal');
|
||||
|
||||
// Initialize all modals
|
||||
try {
|
||||
const modalElements = document.querySelectorAll('.modal');
|
||||
modalElements.forEach(modalElement => {
|
||||
if (modalElement) {
|
||||
const modalInstance = new bootstrap.Modal(modalElement, {
|
||||
backdrop: true,
|
||||
keyboard: true,
|
||||
focus: true
|
||||
});
|
||||
|
||||
// Add click handler for modal triggers
|
||||
const triggers = document.querySelectorAll(`[data-bs-target="#${modalElement.id}"]`);
|
||||
triggers.forEach(trigger => {
|
||||
trigger.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
modalInstance.show();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error initializing modals:', error);
|
||||
}
|
||||
|
||||
// Initialize auth form handlers
|
||||
const loginForm = document.querySelector('#loginModal form');
|
||||
const loginError = document.querySelector('#loginError');
|
||||
const captchaContainer = document.querySelector('.captcha-container');
|
||||
|
||||
if (loginForm) {
|
||||
// Show CAPTCHA if needed
|
||||
if (simpleAuth.needsCaptcha() && captchaContainer) {
|
||||
captchaContainer.style.display = 'flex';
|
||||
}
|
||||
}
|
||||
|
||||
// Handle logout button
|
||||
const logoutButton = document.querySelector('button[name="logoutButton"]');
|
||||
if (logoutButton) {
|
||||
logoutButton.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
await simpleAuth.logout();
|
||||
});
|
||||
}
|
||||
|
||||
// Validate token if authenticated
|
||||
if (simpleAuth.isAuthenticated()) {
|
||||
simpleAuth.validateToken().then(valid => {
|
||||
if (!valid) {
|
||||
if (!localStorage.getItem('validationAttempted')) {
|
||||
localStorage.setItem('validationAttempted', 'true');
|
||||
window.location.reload();
|
||||
} else {
|
||||
localStorage.removeItem('validationAttempted');
|
||||
}
|
||||
} else {
|
||||
localStorage.removeItem('validationAttempted');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Mark initialization as complete
|
||||
window.initializationComplete = true;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
327
Views/template/header.phtml
Normal file → Executable file
327
Views/template/header.phtml
Normal file → Executable file
@@ -4,64 +4,317 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="description" content="EcoBuddy - Sustainable facilities management platform">
|
||||
<meta name="author" content="">
|
||||
<link rel="icon" type="image/x-icon" href="/images/ecoBuddy_x32.png">
|
||||
|
||||
<!-- Bootstrap core CSS from CDN for faster loading -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
|
||||
<!-- CSS theme -->
|
||||
<link href="/public/css/my-style.css" rel="stylesheet">
|
||||
|
||||
<!-- Bootstrap Icons -->
|
||||
<link href="/public/css/bootstrap-icons.css" rel="stylesheet">
|
||||
|
||||
<!-- Leaflet -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
|
||||
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="/css/bootstrap.css" rel="stylesheet">
|
||||
<!-- Bootstrap theme -->
|
||||
<link href="/css/bootstrap-theme.css" rel="stylesheet">
|
||||
<link href="/css/my-style.css" rel="stylesheet">
|
||||
|
||||
<!-- Dynamic page title based on the current page -->
|
||||
<title>Ecobuddy - <?php echo $view->pageTitle; ?></title>
|
||||
|
||||
<!-- Load simplified authentication helper -->
|
||||
<script src="/public/js/simpleAuth.js"></script>
|
||||
|
||||
<!-- Load API client -->
|
||||
<script src="/public/js/apiClient.js"></script>
|
||||
|
||||
<!-- Load facility data script -->
|
||||
<script src="/public/js/facilityData.js"></script>
|
||||
|
||||
<!-- Initialise facility data from PHP server-side data -->
|
||||
<script>
|
||||
<?php if (isset($view->facilityDataSet) && is_array($view->facilityDataSet)): ?>
|
||||
try {
|
||||
// Convert PHP data to JavaScript object with proper encoding
|
||||
// Using JSON_UNESCAPED_SLASHES and JSON_UNESCAPED_UNICODE for proper character handling
|
||||
const initialData = <?php echo json_encode($view->facilityDataSet,
|
||||
JSON_UNESCAPED_SLASHES |
|
||||
JSON_UNESCAPED_UNICODE |
|
||||
JSON_PARTIAL_OUTPUT_ON_ERROR
|
||||
); ?>;
|
||||
|
||||
// Validate and store data in sessionStorage for use across the application
|
||||
if (Array.isArray(initialData) && initialData.length > 0) {
|
||||
sessionStorage.setItem('facilityData', JSON.stringify(initialData));
|
||||
|
||||
// Initialize based on DOM state to ensure scripts run at the right time
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
if (typeof initialiseFacilityData === 'function') {
|
||||
initialiseFacilityData(initialData);
|
||||
}
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (typeof initialiseFacilityData === 'function') {
|
||||
initialiseFacilityData(initialData);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add client-side authentication check to update UI
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Check if user is authenticated on the client side
|
||||
if (window.auth && window.auth.isAuthenticated()) {
|
||||
console.log('User is authenticated on client side');
|
||||
|
||||
// Get user data
|
||||
const user = window.auth.getUser();
|
||||
if (user) {
|
||||
console.log('User data:', user);
|
||||
|
||||
// Hide login button if it exists
|
||||
const loginButton = document.getElementById('loginButton');
|
||||
if (loginButton) {
|
||||
loginButton.style.display = 'none';
|
||||
}
|
||||
|
||||
// Hide login modal if it exists
|
||||
const loginModal = document.getElementById('loginModal');
|
||||
if (loginModal) {
|
||||
loginModal.style.display = 'none';
|
||||
}
|
||||
|
||||
// Show user menu
|
||||
const userMenuContainer = document.createElement('div');
|
||||
userMenuContainer.className = 'user-menu';
|
||||
userMenuContainer.innerHTML = `
|
||||
<div class="user-avatar">
|
||||
<i class="bi bi-person-fill text-success"></i>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-light dropdown-toggle" type="button" id="userMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
${user.username}
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userMenuButton">
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-person me-2"></i>Profile</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-gear me-2"></i>Settings</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><button class="dropdown-item text-danger" id="logoutButton"><i class="bi bi-box-arrow-right me-2"></i>Logout</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Replace login button with user menu
|
||||
if (loginButton) {
|
||||
loginButton.parentNode.replaceChild(userMenuContainer, loginButton);
|
||||
}
|
||||
|
||||
// Add logout button handler
|
||||
const logoutButton = document.getElementById('logoutButton');
|
||||
if (logoutButton) {
|
||||
logoutButton.addEventListener('click', async function() {
|
||||
await window.auth.logout();
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error processing facility data:', error);
|
||||
}
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<nav class="navbar navbar-expand-lg m-2 border rounded-2">
|
||||
<div class="container-fluid">
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<body role="document">
|
||||
<!-- Navigation bar -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm sticky-top">
|
||||
<div class="container-fluid px-3">
|
||||
<!-- Brand logo and name -->
|
||||
<a class="navbar-brand d-flex align-items-center" href="/index.php">
|
||||
<img src="/images/ecoBuddy_x64.png" alt="EcoBuddy Logo" width="48" height="48" class="me-2">
|
||||
<span class="fw-bold text-success">EcoBuddy</span>
|
||||
</a>
|
||||
|
||||
<!-- Mobile menu toggle -->
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarContent"
|
||||
aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/index.php">Ecobuddy <?php echo $view->pageTitle?></a>
|
||||
<div class="collapse navbar-collapse" id="navbarTogglerDemo03">
|
||||
|
||||
<!-- Navigation content -->
|
||||
<div class="collapse navbar-collapse" id="navbarContent">
|
||||
<!-- Main navigation links -->
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="/index.php">Home</a>
|
||||
<a class="nav-link active" aria-current="page" href="/index.php">
|
||||
<i class="bi bi-house-fill me-1"></i>Home
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
<a class="nav-link" href="/map.php">
|
||||
<i class="bi bi-map-fill me-1"></i>Map
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
|
||||
<a class="nav-link" href="/about.php">
|
||||
<i class="bi bi-info-circle-fill me-1"></i>About
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form class="d-flex" role="search">
|
||||
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
|
||||
<button class="btn bg-light btn-outline-light text-dark" type="submit">Search</button>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
|
||||
if ($view->loginError) {
|
||||
require_once('Views/template/loginError.phtml');
|
||||
}
|
||||
if(!$user->isLoggedIn()) {
|
||||
require_once('Views/template/loginModal.phtml');
|
||||
}
|
||||
if($user->isLoggedIn()) {
|
||||
require_once('Views/template/logoutButton.phtml');
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Search and filter controls -->
|
||||
<div class="d-flex flex-column flex-lg-row search-controls mx-auto">
|
||||
<form class="d-flex flex-column flex-lg-row gap-2 w-100" role="search" action="" method="POST">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-sort-alpha-down text-success"></i>
|
||||
</span>
|
||||
<select name="sort" class="form-select border-start-0 filter-control" id="sort">
|
||||
<option value="title">Title</option>
|
||||
<option value="category">Category</option>
|
||||
<option value="status">Status</option>
|
||||
<option value="description">Description</option>
|
||||
<option value="streetName">Street</option>
|
||||
<option value="county">County</option>
|
||||
<option value="town">Town</option>
|
||||
<option value="postcode">Postcode</option>
|
||||
<option value="contributor">Contributor</option>
|
||||
</select>
|
||||
<select class="form-select sort-control" name="dir" id="dir" data-order="asc">
|
||||
<option value="asc">Asc</option>
|
||||
<option value="desc">Desc</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-filter-circle-fill text-success"></i>
|
||||
</span>
|
||||
<select name="filterCat" class="form-select border-start-0 filter-control" id="filterCat">
|
||||
<option value="">All</option>
|
||||
<option value="title">Title</option>
|
||||
<option value="category">Category</option>
|
||||
<option value="status">Status</option>
|
||||
<option value="description">Description</option>
|
||||
<option value="streetName">Street</option>
|
||||
<option value="county">County</option>
|
||||
<option value="town">Town</option>
|
||||
<option value="postcode">Postcode</option>
|
||||
<option value="contributor">Contributor</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-search text-success"></i>
|
||||
</span>
|
||||
<input class="form-control border-start-0" id="searchInput" type="search" name="filter" placeholder="Search..." aria-label="Search">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- User account section -->
|
||||
<div class="ms-lg-3 mt-3 mt-lg-0">
|
||||
<?php if(!$view->user->isLoggedIn()): ?>
|
||||
<button type="button" class="btn btn-success" id="loginButton" data-bs-toggle="modal" data-bs-target="#loginModal">
|
||||
<i class="bi bi-box-arrow-in-right me-1"></i>Login
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<div class="user-menu">
|
||||
<div class="user-avatar">
|
||||
<i class="bi bi-person-fill text-success"></i>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-light dropdown-toggle" type="button" id="userMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<?php echo $view->user->getUsername(); ?>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userMenuButton">
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-person me-2"></i>Profile</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-gear me-2"></i>Settings</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><button class="dropdown-item text-danger" id="logoutButton"><i class="bi bi-box-arrow-right me-2"></i>Logout</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<body role="document">
|
||||
|
||||
<div class="container-lg">
|
||||
<!-- Login Modal -->
|
||||
<?php if(!$view->user->isLoggedIn()): ?>
|
||||
<div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="loginModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-light">
|
||||
<h5 class="modal-title" id="loginModalLabel">
|
||||
<i class="bi bi-box-arrow-in-right text-success me-2"></i>Login to EcoBuddy
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form id="loginForm">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-person text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="username" name="username" placeholder="Enter your username" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-lock text-success"></i>
|
||||
</span>
|
||||
<input type="password" class="form-control border-start-0" id="password" name="password" placeholder="Enter your password" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="loginError" class="alert alert-danger" style="display: none;"></div>
|
||||
|
||||
<div class="row captcha-container" style="display: none;">
|
||||
<!-- CAPTCHA Display -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="captchaCode" class="form-label">CAPTCHA Code</label>
|
||||
<input type="text" class="form-control bg-light" id="captchaCode" name="generatedCaptcha" value="" readonly>
|
||||
</div>
|
||||
|
||||
<!-- CAPTCHA Input -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="captchaInput" class="form-label">Enter CAPTCHA</label>
|
||||
<input type="text" class="form-control" id="captchaInput" name="captchaInput" placeholder="Enter code">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2 mt-4">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-box-arrow-in-right me-2"></i>Login
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<div class="w-100 d-flex justify-content-between align-items-center">
|
||||
<small class="text-muted">Don't have an account? <a href="" onclick="alert('Please contact the administrator to create an account.');" class="text-success">Register</a></small>
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="content" >
|
||||
<!-- Main content container -->
|
||||
<div class="container-fluid py-4 px-3">
|
||||
<div class="row" id="content">
|
||||
|
||||
|
||||
|
||||
|
||||
18
Views/template/loginError.phtml
Normal file → Executable file
18
Views/template/loginError.phtml
Normal file → Executable file
@@ -0,0 +1,18 @@
|
||||
<span class="ms-5 me-5 row alert alert-danger" role="alert"><?= $view->loginError ?></span>
|
||||
<div class="row captcha-container">
|
||||
<!-- CAPTCHA Display -->
|
||||
<div class="form-floating mb-3 col">
|
||||
<input type="text" class="form-control" id="captchaCode" value="<?php
|
||||
// Generate a simple 5-character CAPTCHA
|
||||
$captcha = substr(str_shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"), 0, 5);
|
||||
echo $captcha;
|
||||
?>" readonly>
|
||||
<label for="captchaCode">CAPTCHA Code</label>
|
||||
</div>
|
||||
|
||||
<!-- CAPTCHA Input -->
|
||||
<div class="form-floating mb-3 col">
|
||||
<input type="text" class="form-control" id="captchaInput" name="captchaInput" placeholder="Enter CAPTCHA" required>
|
||||
<label for="captchaInput">Enter CAPTCHA</label>
|
||||
</div>
|
||||
</div>
|
||||
62
Views/template/loginModal.phtml
Normal file → Executable file
62
Views/template/loginModal.phtml
Normal file → Executable file
@@ -1,28 +1,62 @@
|
||||
<button type="button" class="btn bg-primary btn-outline-primary text-light m-1 ms-2" data-bs-toggle="modal" data-bs-target="#loginModal">
|
||||
Login
|
||||
</button>
|
||||
<!-- Login Modal -->
|
||||
<div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="loginModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="loginModalLabel">Login</h5>
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-light">
|
||||
<h5 class="modal-title" id="loginModalLabel">
|
||||
<i class="bi bi-box-arrow-in-right text-success me-2"></i>Login to EcoBuddy
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>">
|
||||
<div class="modal-body p-4">
|
||||
<form id="loginForm">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" id="username" name="username" placeholder="Username" required>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-person text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="username" name="username" placeholder="Enter your username" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" placeholder="Password" required>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-lock text-success"></i>
|
||||
</span>
|
||||
<input type="password" class="form-control border-start-0" id="password" name="password" placeholder="Enter your password" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="loginError" class="alert alert-danger" style="display: none;"></div>
|
||||
|
||||
<div class="row captcha-container" style="display: none;">
|
||||
<!-- CAPTCHA Display -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="captchaCode" class="form-label">CAPTCHA Code</label>
|
||||
<input type="text" class="form-control bg-light" id="captchaCode" name="generatedCaptcha" value="" readonly>
|
||||
</div>
|
||||
|
||||
<!-- CAPTCHA Input -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="captchaInput" class="form-label">Enter CAPTCHA</label>
|
||||
<input type="text" class="form-control" id="captchaInput" name="captchaInput" placeholder="Enter code">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2 mt-4">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-box-arrow-in-right me-2"></i>Login
|
||||
</button>
|
||||
</div>
|
||||
<button type="submit" class="btn bg-primary btn-outline-primary text-light" name="loginButton">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-warning" data-bs-dismiss="modal">Close</button>
|
||||
<div class="modal-footer bg-light">
|
||||
<div class="w-100 d-flex justify-content-between align-items-center">
|
||||
<small class="text-muted">Don't have an account? <a href="" onclick="alert('Please contact the administrator to create an account.');" class="text-success">Register</a></small>
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
6
Views/template/logoutButton.phtml
Normal file → Executable file
6
Views/template/logoutButton.phtml
Normal file → Executable file
@@ -1,4 +1,2 @@
|
||||
<?php echo "<p class='nav-link m-2' style='color: black;'>" . $user->getUsername() . " is logged in.</p>"?>
|
||||
<form class="form-inline my-2 my-lg-0" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?> ">
|
||||
<input class="btn bg-danger btn-outline-danger text-light" type="submit" name="logoutButton" value="Logout">
|
||||
</form>
|
||||
<?php echo "<p class='text-center bg-light border-0 rounded mb-1' style='color: black;'>" . $user->getUsername() . "<span class='bi bi-person-fill'></span></p>"?>
|
||||
<button class="btn bg-danger btn-outline-danger text-light" type="button" id="logoutButton">Logout</button>
|
||||
|
||||
78
Views/template/pagination.phtml
Normal file → Executable file
78
Views/template/pagination.phtml
Normal file → Executable file
@@ -0,0 +1,78 @@
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between align-items-center gap-2">
|
||||
<div class="text-muted small">
|
||||
<span id="paginationInfo" class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle me-2 text-success"></i>
|
||||
<span>Showing facilities</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Pagination controls -->
|
||||
<nav aria-label="Facility table pagination">
|
||||
<ul class="pagination pagination-sm mb-0" id="paginationControls">
|
||||
<!-- First page button -->
|
||||
<li class="page-item">
|
||||
<a class="page-link border-0 text-success" href="#" aria-label="First" id="firstPage">
|
||||
<i class="bi bi-chevron-double-left"></i>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Previous page button -->
|
||||
<li class="page-item">
|
||||
<a class="page-link border-0 text-success" href="#" aria-label="Previous" id="prevPage">
|
||||
<i class="bi bi-chevron-left"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Dynamic page numbers will be inserted here as list items -->
|
||||
|
||||
<!-- Next page button -->
|
||||
<li class="page-item">
|
||||
<a class="page-link border-0 text-success" href="#" aria-label="Next" id="nextPage">
|
||||
<i class="bi bi-chevron-right"></i>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Last page button -->
|
||||
<li class="page-item">
|
||||
<a class="page-link border-0 text-success" href="#" aria-label="Last" id="lastPage">
|
||||
<i class="bi bi-chevron-double-right"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Items per page selector -->
|
||||
<div class="d-flex align-items-center">
|
||||
<label for="itemsPerPage" class="form-label text-muted small mb-0 me-2">Items per page:</label>
|
||||
<select class="form-select form-select-sm" id="itemsPerPage" style="width: 70px;">
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Set up items per page selector
|
||||
const itemsPerPageSelect = document.getElementById('itemsPerPage');
|
||||
if (itemsPerPageSelect) {
|
||||
itemsPerPageSelect.addEventListener('change', function() {
|
||||
// Update items per page in the pagination system
|
||||
if (typeof itemsPerPage !== 'undefined') {
|
||||
itemsPerPage = parseInt(this.value);
|
||||
currentPage = 1; // Reset to first page
|
||||
|
||||
// Recalculate total pages
|
||||
if (typeof filteredData !== 'undefined' && typeof totalPages !== 'undefined') {
|
||||
totalPages = Math.ceil(filteredData.length / itemsPerPage);
|
||||
|
||||
// Update table with new pagination
|
||||
if (typeof updateTableWithPagination === 'function') {
|
||||
updateTableWithPagination();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
107
Views/template/statusModal.phtml
Executable file
107
Views/template/statusModal.phtml
Executable file
@@ -0,0 +1,107 @@
|
||||
<!-- Facility Comments Modal -->
|
||||
<div class="modal fade" id="statusModal" tabindex="-1" aria-labelledby="statusModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-light">
|
||||
<h5 class="modal-title" id="statusModalLabel">
|
||||
<i class="bi bi-chat-square-text text-primary me-2"></i>Facility Comments
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<!-- Add Comment Form (Only shown to logged in users) -->
|
||||
<?php if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true && $_SESSION['access'] >= 1): ?>
|
||||
<div class="mb-4 border-bottom pb-4">
|
||||
<h6 class="fw-bold mb-3">
|
||||
<i class="bi bi-plus-circle text-success me-2"></i>Add New Comment
|
||||
</h6>
|
||||
<form id="commentForm">
|
||||
<input type="hidden" name="action" value="status">
|
||||
<input type="hidden" name="facilityId" id="commentFacilityId" value="">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="commentText" class="form-label">Your Comment</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-pencil text-primary"></i>
|
||||
</span>
|
||||
<textarea class="form-control border-start-0" id="commentText" name="commentText" rows="3" placeholder="Share your thoughts about this facility..." required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-send me-1"></i>Post Comment
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Existing Comments Section -->
|
||||
<div>
|
||||
<h6 class="fw-bold mb-3">
|
||||
<i class="bi bi-chat-square-dots text-primary me-2"></i>Comments
|
||||
</h6>
|
||||
|
||||
<div id="commentsContainer" class="comments-container">
|
||||
<!-- Comments will be loaded here dynamically -->
|
||||
<div class="text-center py-4 text-muted" id="noCommentsMessage">
|
||||
<i class="bi bi-chat-square-text fs-4 d-block mb-2"></i>
|
||||
<p>No comments yet. Be the first to share your thoughts!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Login Prompt for Non-Authenticated Users -->
|
||||
<?php if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true): ?>
|
||||
<div class="alert alert-info mt-3">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<span>Please <a href="#" data-bs-toggle="modal" data-bs-target="#loginModal" data-bs-dismiss="modal">log in</a> to add your comments.</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit Comment Modal -->
|
||||
<div class="modal fade" id="editCommentModal" tabindex="-1" aria-labelledby="editCommentModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-light">
|
||||
<h5 class="modal-title" id="editCommentModalLabel">
|
||||
<i class="bi bi-pencil-square text-primary me-2"></i>Edit Comment
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form id="editCommentForm">
|
||||
<input type="hidden" name="action" value="editComment">
|
||||
<input type="hidden" name="commentId" id="editCommentId" value="">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editCommentText" class="form-label">Edit Your Comment</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-pencil text-primary"></i>
|
||||
</span>
|
||||
<textarea class="form-control border-start-0" id="editCommentText" name="editCommentText" rows="4" placeholder="Update your comment..." required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<div class="w-100 d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="editCommentForm" class="btn btn-primary">
|
||||
<i class="bi bi-check-circle me-1"></i>Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
144
Views/template/updateModal.phtml
Executable file
144
Views/template/updateModal.phtml
Executable file
@@ -0,0 +1,144 @@
|
||||
<!-- Update Facility Modal -->
|
||||
<div class="modal fade" id="updateModal" tabindex="-1" aria-labelledby="updateModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-light">
|
||||
<h5 class="modal-title" id="updateModalLabel">
|
||||
<i class="bi bi-pencil-square text-success me-2"></i>Update Facility
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4">
|
||||
<form id="updateForm">
|
||||
<input type="hidden" name="action" value="update">
|
||||
<input type="hidden" name="idUpdate" value="">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="titlUpdate" class="form-label">Title</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-tag text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="titlUpdate" name="titlUpdate" placeholder="Enter facility title" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="cateUpdate" class="form-label">Category</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-bookmark text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="cateUpdate" name="cateUpdate" placeholder="Enter facility category" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="descUpdate" class="form-label">Description</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-card-text text-success"></i>
|
||||
</span>
|
||||
<textarea class="form-control border-start-0" id="descUpdate" name="descUpdate" placeholder="Enter facility description" rows="3" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="hnumUpdate" class="form-label">House/Building Number</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-house text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="hnumUpdate" name="hnumUpdate" placeholder="Enter number" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="strtUpdate" class="form-label">Street Name</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-signpost text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="strtUpdate" name="strtUpdate" placeholder="Enter street name" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="townUpdate" class="form-label">Town/City</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-building text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="townUpdate" name="townUpdate" placeholder="Enter town/city" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="cntyUpdate" class="form-label">County</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-map text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="cntyUpdate" name="cntyUpdate" placeholder="Enter county" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="postUpdate" class="form-label">Postcode</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-mailbox text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="postUpdate" name="postUpdate" placeholder="Enter postcode" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="latUpdate" class="form-label">Latitude</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-geo-alt text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="latUpdate" name="latUpdate" placeholder="Enter latitude" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="lngUpdate" class="form-label">Longitude</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-geo-alt text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0" id="lngUpdate" name="lngUpdate" placeholder="Enter longitude" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="contUpdate" class="form-label">Contributor</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0">
|
||||
<i class="bi bi-person text-success"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0 bg-light" id="contUpdate" name="contUpdate" placeholder="Original contributor" readonly required>
|
||||
</div>
|
||||
<small class="text-muted">Original contributor of this facility</small>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<div class="w-100 d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="updateForm" class="btn btn-success">
|
||||
<i class="bi bi-check-circle me-1"></i>Update Facility
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
225
add_facilities.py
Normal file
225
add_facilities.py
Normal file
@@ -0,0 +1,225 @@
|
||||
import sqlite3
|
||||
import random
|
||||
|
||||
# Connect to the SQLite database
|
||||
conn = sqlite3.connect('Databases/ecobuddy.sqlite')
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Check if we need to add any new categories
|
||||
cursor.execute("SELECT id FROM ecoCategories")
|
||||
existing_categories = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# Add two new categories
|
||||
new_categories = [
|
||||
(16, "Urban Farms"),
|
||||
(17, "Rainwater Harvesting Systems")
|
||||
]
|
||||
|
||||
for category in new_categories:
|
||||
if category[0] not in existing_categories:
|
||||
cursor.execute("INSERT INTO ecoCategories (id, name) VALUES (?, ?)", category)
|
||||
print(f"Added new category: {category[1]}")
|
||||
|
||||
# Get list of user IDs for contributors
|
||||
cursor.execute("SELECT id FROM ecoUser")
|
||||
user_ids = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# Define 10 new ecological facilities in the UK with accurate location data
|
||||
new_facilities = [
|
||||
{
|
||||
"title": "Community Garden Hackney",
|
||||
"category": 12, # Pollinator Gardens
|
||||
"description": "Urban garden with native plants to support local pollinators",
|
||||
"houseNumber": "45",
|
||||
"streetName": "Dalston Lane",
|
||||
"county": "Greater London",
|
||||
"town": "London",
|
||||
"postcode": "E8 3AH",
|
||||
"lng": -0.0612,
|
||||
"lat": 51.5476,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Recently expanded with new wildflower section",
|
||||
"Volunteer days every Saturday"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Rooftop Solar Farm",
|
||||
"category": 8, # Green Roofs
|
||||
"description": "Combined green roof and solar panel installation on commercial building",
|
||||
"houseNumber": "120",
|
||||
"streetName": "Deansgate",
|
||||
"county": "Greater Manchester",
|
||||
"town": "Manchester",
|
||||
"postcode": "M3 2QJ",
|
||||
"lng": -2.2484,
|
||||
"lat": 53.4808,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Generates power for the entire building"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Edinburgh Tool Library",
|
||||
"category": 15, # Community Tool Libraries
|
||||
"description": "Borrow tools instead of buying them - reducing waste and consumption",
|
||||
"houseNumber": "25",
|
||||
"streetName": "Leith Walk",
|
||||
"county": "Edinburgh",
|
||||
"town": "Edinburgh",
|
||||
"postcode": "EH6 8LN",
|
||||
"lng": -3.1752,
|
||||
"lat": 55.9677,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": []
|
||||
},
|
||||
{
|
||||
"title": "Cardiff Bay Water Refill Station",
|
||||
"category": 9, # Public Water Refill Stations
|
||||
"description": "Free water refill station to reduce plastic bottle usage",
|
||||
"houseNumber": "3",
|
||||
"streetName": "Mermaid Quay",
|
||||
"county": "Cardiff",
|
||||
"town": "Cardiff",
|
||||
"postcode": "CF10 5BZ",
|
||||
"lng": -3.1644,
|
||||
"lat": 51.4644,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Recently cleaned and maintained",
|
||||
"High usage during summer months"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Bristol Urban Farm",
|
||||
"category": 16, # Urban Farms (new category)
|
||||
"description": "Community-run urban farm providing local produce and education",
|
||||
"houseNumber": "18",
|
||||
"streetName": "Stapleton Road",
|
||||
"county": "Bristol",
|
||||
"town": "Bristol",
|
||||
"postcode": "BS5 0RA",
|
||||
"lng": -2.5677,
|
||||
"lat": 51.4635,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Open for volunteers Tuesday-Sunday"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Newcastle Rainwater Collection System",
|
||||
"category": 17, # Rainwater Harvesting Systems (new category)
|
||||
"description": "Public demonstration of rainwater harvesting for garden irrigation",
|
||||
"houseNumber": "55",
|
||||
"streetName": "Northumberland Street",
|
||||
"county": "Tyne and Wear",
|
||||
"town": "Newcastle upon Tyne",
|
||||
"postcode": "NE1 7DH",
|
||||
"lng": -1.6178,
|
||||
"lat": 54.9783,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": []
|
||||
},
|
||||
{
|
||||
"title": "Brighton Beach Solar Bench",
|
||||
"category": 7, # Solar-Powered Benches
|
||||
"description": "Solar-powered bench with USB charging ports and WiFi",
|
||||
"houseNumber": "",
|
||||
"streetName": "Kings Road",
|
||||
"county": "East Sussex",
|
||||
"town": "Brighton",
|
||||
"postcode": "BN1 2FN",
|
||||
"lng": -0.1426,
|
||||
"lat": 50.8214,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Popular spot for tourists",
|
||||
"One USB port currently not working"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Leeds Community Compost Hub",
|
||||
"category": 6, # Community Compost Bins
|
||||
"description": "Large-scale community composting facility for local residents",
|
||||
"houseNumber": "78",
|
||||
"streetName": "Woodhouse Lane",
|
||||
"county": "West Yorkshire",
|
||||
"town": "Leeds",
|
||||
"postcode": "LS2 9JT",
|
||||
"lng": -1.5491,
|
||||
"lat": 53.8067,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"Recently expanded capacity"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Glasgow EV Charging Hub",
|
||||
"category": 4, # Public EV Charging Stations
|
||||
"description": "Multi-vehicle EV charging station with fast chargers",
|
||||
"houseNumber": "42",
|
||||
"streetName": "Buchanan Street",
|
||||
"county": "Glasgow",
|
||||
"town": "Glasgow",
|
||||
"postcode": "G1 3JX",
|
||||
"lng": -4.2526,
|
||||
"lat": 55.8621,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": [
|
||||
"6 charging points available",
|
||||
"24/7 access"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Oxford E-Waste Collection Center",
|
||||
"category": 13, # E-Waste Collection Bins
|
||||
"description": "Dedicated facility for proper disposal and recycling of electronic waste",
|
||||
"houseNumber": "15",
|
||||
"streetName": "St Aldate's",
|
||||
"county": "Oxfordshire",
|
||||
"town": "Oxford",
|
||||
"postcode": "OX1 1BX",
|
||||
"lng": -1.2577,
|
||||
"lat": 51.7520,
|
||||
"contributor": random.choice(user_ids),
|
||||
"status_comments": []
|
||||
}
|
||||
]
|
||||
|
||||
# Insert facilities into the database
|
||||
for facility in new_facilities:
|
||||
cursor.execute("""
|
||||
INSERT INTO ecoFacilities
|
||||
(title, category, description, houseNumber, streetName, county, town, postcode, lng, lat, contributor)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
facility["title"],
|
||||
facility["category"],
|
||||
facility["description"],
|
||||
facility["houseNumber"],
|
||||
facility["streetName"],
|
||||
facility["county"],
|
||||
facility["town"],
|
||||
facility["postcode"],
|
||||
facility["lng"],
|
||||
facility["lat"],
|
||||
facility["contributor"]
|
||||
))
|
||||
|
||||
# Get the ID of the inserted facility
|
||||
facility_id = cursor.lastrowid
|
||||
|
||||
# Add status comments if any
|
||||
for comment in facility["status_comments"]:
|
||||
cursor.execute("""
|
||||
INSERT INTO ecoFacilityStatus (facilityId, statusComment)
|
||||
VALUES (?, ?)
|
||||
""", (facility_id, comment))
|
||||
|
||||
print(f"Added facility: {facility['title']} in {facility['town']}")
|
||||
|
||||
# Commit the changes and close the connection
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print("\nSuccessfully added 10 new ecological facilities to the database.")
|
||||
33
api/admin.php
Normal file
33
api/admin.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin-only API endpoint example
|
||||
*
|
||||
* This endpoint demonstrates how to protect an API route for admin users only
|
||||
* using our simplified authentication approach.
|
||||
*/
|
||||
|
||||
require_once('../Models/User.php');
|
||||
|
||||
// Set content type to JSON
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Check if user is an admin
|
||||
$auth = User::checkAdmin();
|
||||
if (!$auth) {
|
||||
// The checkAdmin method already sent the error response
|
||||
exit;
|
||||
}
|
||||
|
||||
// User is an admin, proceed with the admin-only logic
|
||||
$response = [
|
||||
'status' => 'success',
|
||||
'message' => 'You have access to this admin-only endpoint',
|
||||
'user' => [
|
||||
'id' => $auth['uid'],
|
||||
'username' => $auth['username'],
|
||||
'accessLevel' => $auth['accessLevel']
|
||||
]
|
||||
];
|
||||
|
||||
// Send response
|
||||
echo json_encode($response);
|
||||
51
api/login.php
Normal file
51
api/login.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* Login API endpoint
|
||||
*
|
||||
* This endpoint handles user authentication and returns a JWT token
|
||||
* if the credentials are valid.
|
||||
*/
|
||||
|
||||
require_once('../Models/User.php');
|
||||
|
||||
// Set content type to JSON
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Only allow POST requests
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method not allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Get JSON request body
|
||||
$json = file_get_contents('php://input');
|
||||
$data = json_decode($json, true);
|
||||
|
||||
// Validate request data
|
||||
if (!$data || !isset($data['username']) || !isset($data['password'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Invalid request data']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Authenticate user
|
||||
$user = new User();
|
||||
$token = $user->Authenticate($data['username'], $data['password']);
|
||||
|
||||
if ($token) {
|
||||
// Authentication successful
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'token' => $token,
|
||||
'user' => [
|
||||
'id' => $user->getUserId(),
|
||||
'username' => $user->getUsername(),
|
||||
'accessLevel' => $user->getAccessLevel()
|
||||
]
|
||||
]);
|
||||
} else {
|
||||
// Authentication failed
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Invalid credentials']);
|
||||
}
|
||||
33
api/protected.php
Normal file
33
api/protected.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Protected API endpoint example
|
||||
*
|
||||
* This endpoint demonstrates how to protect an API route using
|
||||
* our simplified authentication approach.
|
||||
*/
|
||||
|
||||
require_once('../Models/User.php');
|
||||
|
||||
// Set content type to JSON
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Check if user is authenticated
|
||||
$auth = User::checkAuth();
|
||||
if (!$auth) {
|
||||
// The checkAuth method already sent the error response
|
||||
exit;
|
||||
}
|
||||
|
||||
// User is authenticated, proceed with the endpoint logic
|
||||
$response = [
|
||||
'status' => 'success',
|
||||
'message' => 'You have access to this protected endpoint',
|
||||
'user' => [
|
||||
'id' => $auth['uid'],
|
||||
'username' => $auth['username'],
|
||||
'accessLevel' => $auth['accessLevel']
|
||||
]
|
||||
];
|
||||
|
||||
// Send response
|
||||
echo json_encode($response);
|
||||
113
auth.php
Normal file
113
auth.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
require_once('Models/AuthService.php');
|
||||
require_once('Models/UserDataSet.php');
|
||||
require_once('Models/User.php');
|
||||
|
||||
// Enable CORS
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type, Authorization');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Handle OPTIONS request
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(200);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$auth = new AuthService();
|
||||
$userDataSet = new UserDataSet();
|
||||
|
||||
// Handle POST request for login
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
// Handle token refresh
|
||||
if (isset($data['action']) && $data['action'] === 'refresh') {
|
||||
if (!isset($data['refreshToken'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Refresh token is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$refreshToken = $data['refreshToken'];
|
||||
$newToken = $auth->refreshToken($refreshToken);
|
||||
|
||||
if (!$newToken) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Invalid or expired refresh token']);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'token' => $newToken
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Handle login
|
||||
if (!isset($data['username']) || !isset($data['password'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Username and password are required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Authenticate user
|
||||
$user = new User();
|
||||
$token = $user->Authenticate($data['username'], $data['password']);
|
||||
|
||||
if ($token) {
|
||||
// Generate refresh token
|
||||
$refreshToken = $auth->generateRefreshToken([
|
||||
'id' => $user->getUserId(),
|
||||
'username' => $user->getUsername(),
|
||||
'accessLevel' => $user->getAccessLevel()
|
||||
]);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'token' => $token,
|
||||
'refreshToken' => $refreshToken,
|
||||
'user' => [
|
||||
'id' => $user->getUserId(),
|
||||
'username' => $user->getUsername(),
|
||||
'accessLevel' => $user->getAccessLevel()
|
||||
]
|
||||
]);
|
||||
} else {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Invalid credentials']);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Handle GET request for token validation
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$auth = User::checkAuth(false);
|
||||
|
||||
if ($auth) {
|
||||
echo json_encode([
|
||||
'valid' => true,
|
||||
'user' => [
|
||||
'id' => $auth['uid'],
|
||||
'username' => $auth['username'],
|
||||
'accessLevel' => $auth['accessLevel']
|
||||
]
|
||||
]);
|
||||
} else {
|
||||
http_response_code(401);
|
||||
echo json_encode(['valid' => false, 'error' => 'Invalid or expired token']);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method not allowed']);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('Auth error: ' . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Server error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
347
bootstrap3.old/css/bootstrap-theme.css
vendored
347
bootstrap3.old/css/bootstrap-theme.css
vendored
@@ -1,347 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap v3.1.1 (http://getbootstrap.com)
|
||||
* Copyright 2011-2014 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
.btn-default,
|
||||
.btn-primary,
|
||||
.btn-success,
|
||||
.btn-info,
|
||||
.btn-warning,
|
||||
.btn-danger {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-primary:active,
|
||||
.btn-success:active,
|
||||
.btn-info:active,
|
||||
.btn-warning:active,
|
||||
.btn-danger:active,
|
||||
.btn-default.active,
|
||||
.btn-primary.active,
|
||||
.btn-success.active,
|
||||
.btn-info.active,
|
||||
.btn-warning.active,
|
||||
.btn-danger.active {
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
}
|
||||
.btn:active,
|
||||
.btn.active {
|
||||
background-image: none;
|
||||
}
|
||||
.btn-default {
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dbdbdb;
|
||||
border-color: #ccc;
|
||||
}
|
||||
.btn-default:hover,
|
||||
.btn-default:focus {
|
||||
background-color: #e0e0e0;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-default.active {
|
||||
background-color: #e0e0e0;
|
||||
border-color: #dbdbdb;
|
||||
}
|
||||
.btn-primary {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #2b669a;
|
||||
}
|
||||
.btn-primary:hover,
|
||||
.btn-primary:focus {
|
||||
background-color: #2d6ca2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-primary:active,
|
||||
.btn-primary.active {
|
||||
background-color: #2d6ca2;
|
||||
border-color: #2b669a;
|
||||
}
|
||||
.btn-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-success:hover,
|
||||
.btn-success:focus {
|
||||
background-color: #419641;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-success:active,
|
||||
.btn-success.active {
|
||||
background-color: #419641;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-info:hover,
|
||||
.btn-info:focus {
|
||||
background-color: #2aabd2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-info:active,
|
||||
.btn-info.active {
|
||||
background-color: #2aabd2;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-warning:hover,
|
||||
.btn-warning:focus {
|
||||
background-color: #eb9316;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-warning:active,
|
||||
.btn-warning.active {
|
||||
background-color: #eb9316;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.btn-danger:hover,
|
||||
.btn-danger:focus {
|
||||
background-color: #c12e2a;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-danger:active,
|
||||
.btn-danger.active {
|
||||
background-color: #c12e2a;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.thumbnail,
|
||||
.img-thumbnail {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.dropdown-menu > li > a:hover,
|
||||
.dropdown-menu > li > a:focus {
|
||||
background-color: #e8e8e8;
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.dropdown-menu > .active > a,
|
||||
.dropdown-menu > .active > a:hover,
|
||||
.dropdown-menu > .active > a:focus {
|
||||
background-color: #357ebd;
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.navbar-default {
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.navbar-default .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.navbar-brand,
|
||||
.navbar-nav > li > a {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
|
||||
}
|
||||
.navbar-inverse {
|
||||
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.navbar-inverse .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);
|
||||
background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
}
|
||||
.navbar-inverse .navbar-brand,
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
|
||||
}
|
||||
.navbar-static-top,
|
||||
.navbar-fixed-top,
|
||||
.navbar-fixed-bottom {
|
||||
border-radius: 0;
|
||||
}
|
||||
.alert {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
}
|
||||
.alert-success {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b2dba1;
|
||||
}
|
||||
.alert-info {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #9acfea;
|
||||
}
|
||||
.alert-warning {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #f5e79e;
|
||||
}
|
||||
.alert-danger {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dca7a7;
|
||||
}
|
||||
.progress {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.list-group {
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.list-group-item.active,
|
||||
.list-group-item.active:hover,
|
||||
.list-group-item.active:focus {
|
||||
text-shadow: 0 -1px 0 #3071a9;
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3278b3;
|
||||
}
|
||||
.panel {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
}
|
||||
.panel-default > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-primary > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-success > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-info > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-warning > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-danger > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.well {
|
||||
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dcdcdc;
|
||||
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-theme.css.map */
|
||||
File diff suppressed because one or more lines are too long
7
bootstrap3.old/css/bootstrap-theme.min.css
vendored
7
bootstrap3.old/css/bootstrap-theme.min.css
vendored
File diff suppressed because one or more lines are too long
5785
bootstrap3.old/css/bootstrap.css
vendored
5785
bootstrap3.old/css/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
7
bootstrap3.old/css/bootstrap.min.css
vendored
7
bootstrap3.old/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
38
bootstrap3.old/css/my-style.css
vendored
38
bootstrap3.old/css/my-style.css
vendored
@@ -1,38 +0,0 @@
|
||||
#title {
|
||||
margin-top: 12px;
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
|
||||
}
|
||||
#menu {
|
||||
border-top: solid 6px #000;
|
||||
background-color: #fff;
|
||||
color: #fff;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#menu a {
|
||||
background-color: #f00;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
#menu a:hover {
|
||||
background-color: #f00;
|
||||
color: #ddd;
|
||||
text-decoration:underline;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#content {
|
||||
background-color: #fff;
|
||||
border-top: solid 6px #f00;
|
||||
|
||||
}
|
||||
|
||||
#footer {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
}
|
||||
1951
bootstrap3.old/js/bootstrap.js
vendored
1951
bootstrap3.old/js/bootstrap.js
vendored
File diff suppressed because it is too large
Load Diff
6
bootstrap3.old/js/bootstrap.min.js
vendored
6
bootstrap3.old/js/bootstrap.min.js
vendored
File diff suppressed because one or more lines are too long
4085
css/bootstrap-grid.css
vendored
4085
css/bootstrap-grid.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
6
css/bootstrap-grid.min.css
vendored
6
css/bootstrap-grid.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4084
css/bootstrap-grid.rtl.css
vendored
4084
css/bootstrap-grid.rtl.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
6
css/bootstrap-grid.rtl.min.css
vendored
6
css/bootstrap-grid.rtl.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
597
css/bootstrap-reboot.css
vendored
597
css/bootstrap-reboot.css
vendored
@@ -1,597 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
||||
File diff suppressed because one or more lines are too long
6
css/bootstrap-reboot.min.css
vendored
6
css/bootstrap-reboot.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
594
css/bootstrap-reboot.rtl.css
vendored
594
css/bootstrap-reboot.rtl.css
vendored
@@ -1,594 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: right;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user