├── .env.example ├── .github ├── depandabot.yml └── workflows │ ├── build-app.yml │ └── run-tests.yml ├── .gitignore ├── Dockerfile ├── README.md ├── backend ├── __init__.py ├── algorithm.py ├── decorators.py ├── forms.py ├── handlers.py ├── models.py └── views │ ├── auth.py │ └── views.py ├── contract └── BookingChain.sol ├── docker-compose.yml ├── globals.py ├── migrations ├── README ├── alembic.ini ├── env.py └── script.py.mako ├── nginx └── conf.d │ └── nginx.conf ├── requirements.txt ├── server.py ├── static ├── bat │ └── MailHandler.php ├── booking │ ├── booking.php │ ├── css │ │ └── booking.css │ ├── font │ │ ├── FontAwesome.otf │ │ ├── font-awesome.css │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── icomoon.dev.svg │ │ ├── icomoon.eot │ │ ├── icomoon.svg │ │ ├── icomoon.ttf │ │ └── icomoon.woff │ ├── js │ │ ├── booking.js │ │ ├── jquery-ui-1.10.3.custom.min.js │ │ ├── jquery.fancyform.js │ │ ├── jquery.placeholder.js │ │ └── regula.js │ └── less │ │ ├── booking.less │ │ └── mixins.less ├── css │ ├── adipoli.css │ ├── camera.css │ ├── chat.css │ ├── detail-group.css │ ├── font-awesome.css │ ├── form.css │ ├── grid.css │ ├── ie.css │ ├── owl.carousel.css │ ├── reset.css │ ├── skeleton.css │ ├── style.css │ ├── superfish.css │ └── touchTouch.css ├── demo.txt ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── images │ ├── DTU-Campus.jpg │ ├── a.jpg │ ├── arrows.png │ ├── arrowws.png │ ├── big1.jpg │ ├── big2.jpg │ ├── big3.jpg │ ├── big4.jpg │ ├── big5.jpg │ ├── big6.jpg │ ├── big7.jpg │ ├── big8.jpg │ ├── big9.jpg │ ├── camera-loader.gif │ ├── capt_bg.png │ ├── comm.jpg │ ├── cost.jpg │ ├── cost1.jpg │ ├── dtu2.jpg │ ├── dtu3.png │ ├── dtu4.jpg │ ├── dtutoramaecl.png │ ├── icon1.png │ ├── icon2.png │ ├── icon3.png │ ├── icon4.png │ ├── icon5.jpg │ ├── imgonline-com-ua-resize-ldHHNkkIfP5vwUWa (1).jpg │ ├── loc.jpg │ ├── logo.png │ ├── magnifier.png │ ├── menu_bg.png │ ├── nsit1.jpg │ ├── nsit2.jpg │ ├── nsit3.jpg │ ├── nsit4.jpg │ ├── page1_img1.jpg │ ├── page1_img2.jpg │ ├── page1_img3.jpg │ ├── page2_img1.jpg │ ├── page3_img1.jpg │ ├── page3_img2.jpg │ ├── page3_img3.jpg │ ├── page3_img4.jpg │ ├── page3_img5.jpg │ ├── page3_img6.jpg │ ├── page3_img7.jpg │ ├── page3_img8.jpg │ ├── page3_img9.jpg │ ├── page4_img1.jpg │ ├── page4_img3.jpg │ ├── page4_img4.jpg │ ├── page4_img5.jpg │ ├── page4_img6.jpg │ ├── page4_img7.jpg │ ├── page4_img8.jpg │ ├── page4_img9.jpg │ ├── preloader.gif │ ├── prevnext.png │ ├── quotes.png │ ├── serv.jpg │ ├── serv1.jpg │ ├── slide.jpg │ ├── slide1.jpg │ ├── slide2.jpg │ └── spacer.png ├── js │ ├── TMForm.js │ ├── Web3Payments.js │ ├── camera.js │ ├── html5shiv.js │ ├── jquery-migrate-1.2.1.js │ ├── jquery.adipoli.js │ ├── jquery.easing.1.3.js │ ├── jquery.equalheights.js │ ├── jquery.js │ ├── jquery.mobile.customized.min.js │ ├── jquery.mobilemenu.js │ ├── jquery.ui.totop.js │ ├── owl.carousel.js │ ├── script.js │ ├── superfish.js │ └── touchTouch.jquery.js └── logo.png ├── templates ├── base.html ├── chat.html ├── contact.html ├── detail-group.html ├── index.html ├── login.html ├── navbar.html ├── register.html └── services.html └── tests ├── functional ├── test_login.py └── test_register.py └── unit └── test_models.py /.env.example: -------------------------------------------------------------------------------- 1 | SECRET_KEY=sadaskljdweropdw11 2 | GOOGLE_MAPS_APIKEY=Adsdkdfktest 3 | ORG_SOURCE=delhi -------------------------------------------------------------------------------- /.github/depandabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | open-pull-requests-limit: 100 -------------------------------------------------------------------------------- /.github/workflows/build-app.yml: -------------------------------------------------------------------------------- 1 | name: OSMD BookCab 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | python-version: [3.10.9] 14 | steps: 15 | - uses: actions/checkout@main 16 | - name: Initialize Python 3.10.9 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: ${{matrix.python-version}} 20 | - name: Install dependencies 21 | run: | 22 | python -m pip install --upgrade pip 23 | pip install -r requirements.txt 24 | python server.py -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: OSMD BookCab run tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | python-version: [3.10.9] 14 | steps: 15 | - uses: actions/checkout@main 16 | - name: Initialize Python 3.10.9 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: ${{matrix.python-version}} 20 | - name: Install dependencies and run tests 21 | run: | 22 | python -m pip install --upgrade pip 23 | pip install -r requirements.txt 24 | python -m pytest -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | __pycache__ 3 | .env 4 | instance 5 | *.db -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10 2 | ENV PYTHONUNBUFFERED 1 3 | WORKDIR /code 4 | COPY requirements.txt requirements.txt ./ 5 | RUN pip install -r requirements.txt 6 | COPY . ./ 7 | EXPOSE 8000 8 | CMD ["sh", "./deploy.sh"] 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

logo

2 | 3 | # OSMD Book Cab (One Source Multiple Destination) 4 | 5 | - [About Project](#About-Project) 6 | 7 | - [Working](#Working) 8 | - [Login](#Login) 9 | - [Booking Cab](#Booking-Cab) 10 | - [Your Bookings](#Your-Bookings) 11 | - [Accepted Bookings](#Bookings-Accepted) 12 | - [Individual Bookings](#Individual-Bookings) 13 | - [Chat Functionality](#Chats) 14 | 15 | - [Getting Started](#Getting-Started) 16 | - [How to Add Google Maps Api](#oogle-api) 17 | - [How to Add Redis Host](#redis-host) 18 | - [Setup And Run the Application](#run) 19 | 20 | 21 | 22 | # About OSMD Book Cab 23 | 24 | - Book Cab is a web app that optimizes the rideshare booking approach. This app serves as a single source to help users find the shortest path for multiple destination, shared rides. 25 | 26 | - The goal of this project is to figure out the shortest feasible path from a given starting point using an algorithm. The performance of the developed algorithm will be studied for practical use. 27 | 28 | 29 | # How it Works 30 | - Works on Bellman-Ford algorithm to compute shortest and optimized path by considering each location as a vertex of the graph. 31 | - The booking is then paired with max 4 people based on the route and low cost. 32 | 33 | ### What is Bellman-Ford Algorithm 34 | The Bellman–Ford algorithm is an algorithm that computes shortest paths from a single source vertex to all of the other vertices in a weighted digraph. 35 | 36 | ## Features and Interfaces 37 | 38 | 1. Registration page 39 | - ![image](https://user-images.githubusercontent.com/68425016/152768563-2832bac6-9097-4ddc-986d-0df97379b1cd.png) 40 | 41 | 2. Booking page 42 | - ![image](https://user-images.githubusercontent.com/68425016/152768627-17fb7908-3da2-421c-ad3c-7298d8b4b55a.png) 43 | 44 | 3. Your bookings 45 | - ![image](https://user-images.githubusercontent.com/68425016/152768780-d900ff3b-6d50-40f2-9f63-57a98df07017.png) 46 | 47 | 4. Bookings accepted 48 | - Booking accepted but payment pending 49 | - ![image](https://user-images.githubusercontent.com/68425016/207077739-6405d320-1edf-45d6-b92d-3cae063f4176.png) 50 | - paying using ethereum (SepoliaETH) 51 | - ![image](https://user-images.githubusercontent.com/68425016/207078028-ed56e3ee-0c54-414d-9211-11d2e2fc7db5.png) 52 | 53 | 54 | 5. Bookings accepted 55 | - Booking info of individuals who will be sitting in the same shared cab. 56 | - ![image](https://user-images.githubusercontent.com/68425016/152769026-09d94746-f7d9-4d7b-9852-8ffad5331587.png) 57 | 58 | 5. Your route 59 | - See your route on your bookings accepted page. 60 | - ![image](https://user-images.githubusercontent.com/68425016/201683649-67dd6a5c-d217-4a90-983c-fd265760774a.png) 61 | 62 | 63 | 6. Chat Functionality 64 | - ![image](https://user-images.githubusercontent.com/68425016/201581222-b6841c98-1001-47d7-bfbe-d82e33eca63b.png) 65 | 66 | 67 | 68 | 69 | ## Getting Started 70 | 71 | 72 | 73 | - #### Add google maps API. 74 | 75 | - Create your billing account at [google maps platform](https://mapsplatform.google.com/) (google console). 76 | - Generate Api key to access the services. 77 | - Add the api to .env file. 78 | 79 | 80 | 81 | - #### Setup using docker 82 | - ````docker-compose build```` 83 | - ````docker-compose up```` 84 | 85 | 86 | - #### Setup 87 | - ```pip install -r requirements.txt``` 88 | - ```python server.py``` 89 | 90 | - #### Run Tests using pytest 91 | - ```pip install pytest``` 92 | - ```python -m pytest``` 93 | -------------------------------------------------------------------------------- /backend/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | from flask import Flask 4 | from globals import ( 5 | UPLOAD_FOLDER, 6 | DB_NAME, 7 | SECRET_KEY, 8 | db, 9 | migrate, 10 | STATIC_URI, 11 | TEMPLATES_URI 12 | ) 13 | 14 | 15 | def create_app(testing=False): 16 | 17 | app = Flask(__name__) 18 | 19 | app.config["SECRET_KEY"] = SECRET_KEY 20 | app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{DB_NAME}" 21 | app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER 22 | app.config["TESTING"] = testing 23 | app.static_folder = STATIC_URI 24 | app.template_folder = TEMPLATES_URI 25 | 26 | migrate.init_app(app,db) 27 | db.init_app(app) 28 | 29 | 30 | from backend.views.auth import auth 31 | from backend.views.views import views 32 | 33 | app.register_blueprint(views,url_prefix='/') 34 | app.register_blueprint(auth,url_prefix='/auth/') 35 | 36 | 37 | from backend.models import ( 38 | User, 39 | Booking, 40 | CabGroup, 41 | Source 42 | ) 43 | 44 | create_database(app) 45 | 46 | return app 47 | 48 | def create_database(app): 49 | 50 | if not os.path.exists(DB_NAME): 51 | with app.app_context(): 52 | db.create_all() 53 | print("database created...") -------------------------------------------------------------------------------- /backend/algorithm.py: -------------------------------------------------------------------------------- 1 | import math 2 | import os 3 | from itertools import permutations 4 | from backend.models import ( 5 | Booking, 6 | Source 7 | ) 8 | from globals import gmaps 9 | from globals import SOURCE as home_source 10 | 11 | 12 | def get_distance(src, dest): 13 | 14 | ''' 15 | Calculate distance between source and single destincation 16 | this will be used with duration to calculate the priority order to dropping a user 17 | ''' 18 | 19 | if src + dest in distance_matrix_map: 20 | return distance_matrix_map[src + dest] 21 | else : 22 | my_dist = gmaps.distance_matrix(src, dest)['rows'][0]['elements'][0] 23 | 24 | if my_dist["status"]=="OK": 25 | distance_matrix_map[src + dest] = my_dist['distance']['value'] 26 | distance_matrix_map[dest + src] = my_dist['distance']['value'] 27 | time_matrix_map[src + dest] = my_dist['duration']['value'] 28 | time_matrix_map[dest + src] = my_dist['duration']['value'] 29 | return distance_matrix_map[src + dest] 30 | 31 | return 0 32 | 33 | def get_duration(src, dest) : 34 | 35 | ''' 36 | Calculate duration between source and single destincation 37 | this will be used with distance to calculate the priority order to dropping a user 38 | ''' 39 | 40 | if (src + dest) in time_matrix_map: 41 | return time_matrix_map[src + dest] 42 | else : 43 | my_dist = gmaps.distance_matrix(src, dest)['rows'][0]['elements'][0] 44 | distance_matrix_map[src + dest] = my_dist['distance']['value'] 45 | distance_matrix_map[dest + src] = my_dist['distance']['value'] 46 | time_matrix_map[src + dest] = my_dist['duration']['value'] 47 | time_matrix_map[dest + src] = my_dist['duration']['value'] 48 | return time_matrix_map[src + dest] 49 | 50 | 51 | 52 | 53 | def get_cost(duration,distance,milage,min_cost=50,seater=4): 54 | 55 | ''' 56 | Calculates fuel cost of the registerd vehical to get best price 57 | accoring to the deployed cars performance 58 | ''' 59 | 60 | fuel_price = 0 61 | 62 | fuel_to_burn = distance/milage 63 | base_cost = (fuel_to_burn*fuel_price) + min_cost 64 | additional_cost = (base_cost/100)*seater # seater cost 65 | gst = ((base_cost+additional_cost)/100)*18 # 18 % gst 66 | 67 | total_cost = base_cost+additional_cost+gst 68 | 69 | return total_cost 70 | 71 | 72 | distance_matrix_map = dict() 73 | time_matrix_map = dict() 74 | 75 | 76 | 77 | class dpstate: 78 | def __init__(self, taxino, curloc, curtime, users_in_taxi): 79 | self.taxino = taxino 80 | self.curloc = curloc 81 | self.curtime = curtime 82 | self.users_in_taxi = users_in_taxi 83 | 84 | def __hash__(self): 85 | val = 0 86 | for i in self.users_in_taxi: 87 | val += i * i 88 | return hash((self.taxino, self.curloc, self.curtime)) + val 89 | 90 | def __eq__(self, other): 91 | return (self.taxino, self.curloc, self.curtime, self.users_in_taxi) == (other.taxino, other.curloc, other.curtime, other.users_in_taxi) 92 | 93 | def to_string(self): 94 | return self.taxino + " " + self.curloc + " " + self.curtime + " " + self.users_in_taxi 95 | 96 | 97 | class User: 98 | 99 | def __init__(self, id, destination,booking_id): 100 | self.id = id 101 | self.destination = destination 102 | self.booking_id = booking_id 103 | 104 | def to_string(self): 105 | return self.id + " " + self.destination 106 | 107 | 108 | class UserAttributes: 109 | 110 | def __init__(self, userid, destination, booking_id ,distance, time, cost): 111 | self.userid = userid 112 | self.destination = destination 113 | self.booking_id = booking_id 114 | self.distance = distance 115 | self.time = time 116 | self.cost = cost 117 | 118 | def to_string(self): 119 | return str(self.userid) + " " + self.destination + " " + str(self.distance) + " " + str(self.time) + " " + str(self.cost) 120 | 121 | 122 | 123 | cache = dict() 124 | users = list() 125 | groups = list() 126 | n = 0 127 | answer = 1e9 128 | 129 | 130 | def solve(taxino, curloc, curtime, users_in_taxi, cost, best_config): 131 | 132 | global answer 133 | if users_in_taxi.count(0) + users_in_taxi.count(1) == 0: 134 | if cost < answer: 135 | best_config.clear() 136 | for i in users_in_taxi: 137 | best_config.append(i) 138 | answer = cost 139 | return 0 140 | if dpstate(taxino, curloc, curtime, users_in_taxi) in cache: 141 | return cache[dpstate(taxino, curloc, curtime, users_in_taxi)] 142 | 143 | res = 1e9 144 | 145 | # Move on to new taxi if all passengers have reached their destination 146 | if curloc != home_source and users_in_taxi.count(1) == 0: 147 | return solve(taxino + 1, home_source, 0, users_in_taxi, cost, best_config) 148 | 149 | # Try picking up passengers if there is space and we are at source and calculate best result 150 | picked_up = users_in_taxi.count(1) 151 | for i in range(0, n): 152 | 153 | if picked_up < 4 and users_in_taxi[i] == 0 and curloc == home_source: 154 | users_in_taxi[i] = 1 155 | res = min(res, solve(taxino, curloc, curtime, users_in_taxi, cost, best_config)) 156 | users_in_taxi[i] = 0 157 | 158 | # Try dropping off passengers and see if it yields best result 159 | for i in range(0, n) : 160 | 161 | if users_in_taxi[i] == 1: 162 | users_in_taxi[i] = taxino 163 | res = min(res, get_distance(curloc, users[i].destination) + solve(taxino, users[i].destination, curtime + get_distance(curloc, users[i].destination), users_in_taxi, cost + get_distance(curloc, users[i].destination), best_config)) 164 | users_in_taxi[i] = 1 165 | 166 | cache[dpstate(taxino, curloc, curtime, users_in_taxi)] = res 167 | 168 | return res 169 | 170 | 171 | def cost_calculator(dist, tot_dist, min_cost, tot_cost) : 172 | 173 | ''' 174 | calculate cost by considering distance of each user from source 175 | and total distance coverd in then end. 176 | considering: 177 | - min cost which should be paid 178 | ''' 179 | 180 | val = (1.0 * dist) / (1.0 * tot_dist) 181 | val *= tot_cost 182 | val = math.floor(val) 183 | val = max(val, min_cost) 184 | return val/10 185 | 186 | 187 | def print_group_pattern(users_in_taxi) : 188 | users_done = 0 189 | 190 | try: 191 | for i in range(2, 1000): 192 | if users_done >= n: 193 | return 194 | 195 | 196 | cur_cab_users = list() 197 | print("Taxi #" + str(i - 1) + ": ") 198 | for j in range(0, n): 199 | if users_in_taxi[j] == i: 200 | print(str(users[j].id) + " ") 201 | users_done += 1 202 | cur_cab_users.append(users[j]) 203 | print("") 204 | # Process current cab users to form person attribute object for each of the user sitting in this cab 205 | tot_users = len(cur_cab_users) 206 | if tot_users == 0 : 207 | return 208 | # Groups is a list which is the final object to be sent to front end and comprises of a list of "group" and each "group" is a list of "UserAttributes" 209 | # We are here to find current group details 210 | group = list() 211 | perm = list() 212 | for x in range(0, tot_users): 213 | perm.append(x) 214 | perm_list = permutations(perm) 215 | 216 | min_dist = 1e9 217 | for candidate in perm_list: 218 | cur_dist = get_distance(home_source, cur_cab_users[candidate[0]].destination) 219 | for idx in range(1, tot_users): 220 | cur_dist += get_distance(cur_cab_users[candidate[idx - 1]].destination, cur_cab_users[candidate[idx]].destination) 221 | 222 | if(cur_dist > min_dist): 223 | continue 224 | # Update the best group 225 | print(candidate) 226 | group.clear() 227 | min_dist = cur_dist 228 | dur_so_far = get_duration(home_source, cur_cab_users[candidate[0]].destination) 229 | dist_so_far = get_distance(home_source, cur_cab_users[candidate[0]].destination) 230 | minimum_cost = 53 231 | total_cost = 60 + 12 * ((1.0 * cur_dist)/ (1000.0)) 232 | 233 | group.append(UserAttributes(cur_cab_users[candidate[0]].id, cur_cab_users[candidate[0]].destination,cur_cab_users[candidate[0]].booking_id, 234 | dist_so_far, dur_so_far, cost_calculator(dist_so_far, cur_dist, minimum_cost, total_cost))) 235 | 236 | for idx in range(1, tot_users): 237 | dur_so_far += get_duration(cur_cab_users[candidate[idx - 1]].destination, cur_cab_users[candidate[idx]].destination) 238 | dist_so_far = get_distance(cur_cab_users[candidate[idx - 1]].destination, cur_cab_users[candidate[idx]].destination) 239 | 240 | group.append(UserAttributes(cur_cab_users[candidate[idx]].id, cur_cab_users[candidate[idx]].destination,cur_cab_users[candidate[idx]].booking_id, 241 | dist_so_far, dur_so_far,cost_calculator(dist_so_far, cur_dist, minimum_cost, total_cost))) 242 | 243 | groups.append(group) 244 | 245 | except: 246 | print("") 247 | 248 | 249 | def populate_user_list(bookings) : 250 | users = list() 251 | 252 | try: 253 | 254 | for booking in bookings: 255 | user_id = booking.user 256 | dest = booking.destination 257 | booking_id = booking.id 258 | print(booking_id,"booking") 259 | users.append(User(user_id, dest,booking_id)) 260 | 261 | except Exception as e: 262 | print("err",e) 263 | 264 | return users 265 | 266 | 267 | def main(): 268 | 269 | global n 270 | global users 271 | global groups 272 | 273 | bookings = Booking.query.filter_by(status=0).all() 274 | users = populate_user_list(bookings) 275 | n = len(users) 276 | users_in_taxi = [0 for i in range(n)] 277 | best_config = list() 278 | mincost = solve(2, home_source, 0, users_in_taxi, 0, best_config) 279 | 280 | print_group_pattern(best_config) 281 | 282 | # dividing people in groups of 4 283 | return groups 284 | 285 | 286 | 287 | 288 | -------------------------------------------------------------------------------- /backend/decorators.py: -------------------------------------------------------------------------------- 1 | from flask import session, redirect, url_for 2 | from functools import wraps 3 | from backend.models import User 4 | 5 | def is_authenticated(func): 6 | ''' 7 | Decorator to check if user is authenticated before accessing the route 8 | else redirect to login 9 | ''' 10 | @wraps(func) 11 | def wrapper(*args,**kwargs): 12 | 13 | urs = session.get("user",None) 14 | user_obj = User.query.filter_by(email=urs).first() 15 | if urs == None or user_obj == None: 16 | return redirect(url_for("auth.login")) 17 | 18 | return func(*args,**kwargs) 19 | 20 | return wrapper -------------------------------------------------------------------------------- /backend/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm 2 | from wtforms import ( 3 | EmailField, 4 | PasswordField, 5 | StringField, 6 | SubmitField, 7 | TimeField, 8 | DateField, 9 | ) 10 | from wtforms.validators import DataRequired,Length,Email 11 | 12 | 13 | class RegisterForm(FlaskForm): 14 | 15 | name = StringField('Name',validators=[DataRequired(),Length(5)]) 16 | phone_number = StringField("Phone Number",validators=[DataRequired(),Length(12)]) 17 | email = EmailField("Email",validators=[DataRequired(),Email()]) 18 | password = PasswordField("Password",validators=[DataRequired(),Length(8)]) 19 | submit = SubmitField("Register") 20 | 21 | 22 | class LoginForm(FlaskForm): 23 | 24 | email = EmailField("Email",validators=[DataRequired(),Email()]) 25 | password = PasswordField("Password",validators=[DataRequired(),Length(8)]) 26 | submit = SubmitField("Log In") 27 | 28 | 29 | class BookCabForm(FlaskForm): 30 | 31 | destination = StringField('Destination',validators=[DataRequired()]) 32 | time = TimeField("Time",validators=[]) 33 | date = DateField("Date",validators=[]) 34 | 35 | -------------------------------------------------------------------------------- /backend/handlers.py: -------------------------------------------------------------------------------- 1 | 2 | # Contains event handlers for flask socket io events 3 | 4 | from flask_socketio import join_room, leave_room, send 5 | from flask import session 6 | 7 | try: 8 | from __main__ import socketio 9 | except ImportError: 10 | from server import socketio 11 | 12 | @socketio.on('join') 13 | def on_join_room(data): 14 | 15 | ''' 16 | on call user will be added to the room sent by the user 17 | ''' 18 | 19 | username = data['username'] 20 | room = data['room'] 21 | join_room(room) 22 | send({"user":session["user"],"message":"has enterd the chat"}, to=room,broadcast=True) 23 | 24 | @socketio.on('leave') 25 | def on_leave(data): 26 | 27 | ''' 28 | on call user will be removed from the room 29 | ''' 30 | 31 | username = data['username'] 32 | room = data['room'] 33 | leave_room(room) 34 | send({"user":session["user"],"message":"has left the chat"}, to=room,broadcast=True) 35 | 36 | 37 | @socketio.on('message') 38 | def handel_message(json): 39 | 40 | ''' 41 | messages from users will be broadcasted 42 | ''' 43 | 44 | room = json["room"] 45 | message = json["message"] 46 | 47 | if message != "User Connected": 48 | send({"user":session["user"],"message":message},room=room,broadcast=True) 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /backend/models.py: -------------------------------------------------------------------------------- 1 | from globals import db 2 | from sqlalchemy.sql import func 3 | 4 | class CabGroup(db.Model): 5 | id = db.Column(db.Integer,primary_key=True) 6 | name = db.Column(db.String(120),nullable=False) 7 | bookings = db.relationship('Booking',backref="cabgroup_bookings") 8 | 9 | 10 | 11 | # root destination of the organization offering the services 12 | class Source(db.Model): 13 | id = db.Column(db.Integer,primary_key=True) 14 | location_name = db.Column(db.String(1000),nullable=False) 15 | 16 | 17 | 18 | class Booking(db.Model): 19 | 20 | id = db.Column(db.Integer,primary_key=True) 21 | destination = db.Column(db.String(50),nullable=True) 22 | status = db.Column(db.Integer,nullable=True) # 0 = booking ongoing | 1 = payment pending | 2 = booking accepted 23 | date = db.Column(db.DateTime(timezone=True), default=func.now()) 24 | cost = db.Column(db.Integer,nullable=True) 25 | distance = db.Column(db.Integer,nullable=True) 26 | booking_hash = db.Column(db.String(500),nullable=False) 27 | 28 | group = db.Column(db.Integer,db.ForeignKey('cab_group.id')) 29 | user = db.Column(db.Integer,db.ForeignKey('user.id')) 30 | def __str__(self): 31 | return f"{self.user} {self.destination} {self.status} {self.user.id}" 32 | 33 | 34 | class User(db.Model): 35 | 36 | id = db.Column(db.Integer,primary_key=True) 37 | name = db.Column(db.String(50),nullable=False) 38 | email = db.Column(db.String(200),unique=True,nullable=False) 39 | phone_number = db.Column(db.String(16),nullable=True) 40 | password = db.Column(db.String(16),nullable=False) 41 | bookings = db.relationship('Booking',backref="user_bookings") 42 | 43 | created_at = db.Column(db.DateTime(timezone=True), default=func.now()) 44 | update_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) 45 | 46 | -------------------------------------------------------------------------------- /backend/views/auth.py: -------------------------------------------------------------------------------- 1 | from flask import ( 2 | Blueprint, 3 | render_template, 4 | session, 5 | request, 6 | redirect, 7 | flash, 8 | url_for 9 | ) 10 | from backend.forms import RegisterForm,LoginForm 11 | from backend.models import User 12 | from werkzeug.security import generate_password_hash, check_password_hash 13 | from globals import db 14 | 15 | auth = Blueprint("auth",__name__) 16 | 17 | @auth.route("/register",methods=["POST","GET"]) 18 | def register(): 19 | 20 | user = session.get("user",None) 21 | user_obj = User.query.filter_by(email=user).first() 22 | form = RegisterForm() 23 | 24 | if user_obj!=None: 25 | return redirect(url_for("views.home")) 26 | 27 | if request.method == "POST": 28 | 29 | if form.validate_on_submit(): 30 | if User.query.filter_by(email=form.data["email"]).first() == None: 31 | 32 | 33 | new_user = User( 34 | name = form.data["name"], 35 | email = form.data["email"], 36 | phone_number = form.data["phone_number"], 37 | password = generate_password_hash(form.data["password"],'sha256') 38 | ) 39 | 40 | db.session.add(new_user) 41 | db.session.commit() 42 | 43 | flash("User created successfully") 44 | return redirect(url_for("auth.login")) 45 | 46 | flash("Email already exists") 47 | 48 | else: 49 | flash(form.errors) 50 | 51 | 52 | return render_template( 53 | 'register.html', 54 | user = user, 55 | form = form 56 | ) 57 | 58 | @auth.route('/login',methods=['POST','GET']) 59 | def login(): 60 | 61 | user = session.get("user",None) 62 | user_obj = User.query.filter_by(email=user).first() 63 | if user_obj!=None: 64 | return redirect(url_for("views.home")) 65 | 66 | form = LoginForm() 67 | 68 | if request.method == "POST": 69 | 70 | if form.validate_on_submit(): 71 | 72 | user = User.query.filter_by( 73 | email = form.data["email"] 74 | ).first() 75 | 76 | if user and check_password_hash(user.password,form.data["password"]): 77 | session["user"] = user.email 78 | session["username"] = user.name 79 | return redirect(url_for("views.home")) 80 | 81 | flash("Incorrect Credentials") 82 | 83 | else: 84 | flash(form.errors) 85 | 86 | 87 | 88 | return render_template( 89 | 'login.html', 90 | user = user, 91 | form = form 92 | ) 93 | 94 | 95 | 96 | @auth.route("/logout",methods=["GET"]) 97 | def logout(): 98 | 99 | session["user"] = None 100 | return redirect(url_for("auth.login")) -------------------------------------------------------------------------------- /backend/views/views.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | import random 3 | 4 | from flask import Blueprint, render_template, session, request, flash, redirect, url_for, make_response 5 | from flask_cors import CORS,cross_origin 6 | 7 | from backend.decorators import is_authenticated 8 | from backend.forms import BookCabForm 9 | from backend.models import Booking, User, CabGroup 10 | from backend.algorithm import main 11 | 12 | from globals import maps_apikey 13 | from globals import db, maps_apikey, SOURCE 14 | 15 | 16 | views = Blueprint("views",__name__) 17 | 18 | @views.route("/",methods=["GET","POST"]) 19 | @is_authenticated 20 | def home(): 21 | 22 | form = BookCabForm() 23 | 24 | if request.method == "POST": 25 | 26 | if form.validate_on_submit(): 27 | destination = form.data["destination"] 28 | 29 | try: 30 | # booking having status code ongoing 31 | bookings_ongoing = Booking.query.filter_by(status=0).all() 32 | 33 | # create bookings if there are more than 4 ongoing request in queue 34 | user = User.query.filter_by(email=session["user"]).first() 35 | booking_hash = str(uuid.uuid1()) 36 | curr_booking = Booking( 37 | destination=destination, 38 | user=user.id, 39 | status=0, 40 | booking_hash=booking_hash 41 | ) 42 | db.session.add(curr_booking) 43 | db.session.commit() 44 | 45 | if len(bookings_ongoing)>=4: 46 | print(bookings_ongoing) 47 | groups = main() 48 | 49 | for group in groups: 50 | name = f"grp{random.randint(1,10000)}:{random.randbytes(10000)}" 51 | grp = CabGroup(name=name) 52 | db.session.add(grp) 53 | db.session.commit() 54 | for usrAttr in group: 55 | 56 | booking_a = Booking.query.filter_by(id=usrAttr.booking_id).all() 57 | 58 | for booking_ in booking_a: 59 | 60 | booking_.status = 1 61 | booking_.group = grp.id 62 | booking_.cost = usrAttr.cost 63 | booking_.distance = usrAttr.distance 64 | 65 | db.session.add_all(booking_a) 66 | db.session.commit() 67 | 68 | flash("Booking added") 69 | 70 | else: 71 | flash("request added successfuly") 72 | 73 | 74 | except Exception as e: 75 | print(e,"=========") 76 | flash("allocation failed try again later!") 77 | 78 | else: 79 | flash(form.errors) 80 | 81 | return render_template( 82 | "index.html", 83 | user = session["user"], 84 | form = form, 85 | google_maps_apikey = maps_apikey 86 | ) 87 | 88 | 89 | @views.route("/services",methods=["GET"]) 90 | @is_authenticated 91 | def services(): 92 | 93 | user = User.query.filter_by(email=session["user"]).first() 94 | if user == None: 95 | return redirect(url_for("auth.login")) 96 | 97 | curr_bookings = Booking.query.filter_by(user=user.id).all() 98 | 99 | return render_template( 100 | "services.html", 101 | user = session["user"], 102 | bookings = curr_bookings 103 | ) 104 | 105 | @views.route("/contact",methods=["GET"]) 106 | @is_authenticated 107 | def contact(): 108 | 109 | user = User.query.filter_by(email=session["user"]).first() 110 | if user == None: 111 | return redirect(url_for("auth.login")) 112 | 113 | return render_template( 114 | "contact.html", 115 | user = session["user"], 116 | MAPS_APIKEY = maps_apikey, 117 | SOURCE_LOCATION = SOURCE 118 | ) 119 | 120 | 121 | @views.route("/detail_group/",methods=["GET"]) 122 | @is_authenticated 123 | def detail_group(pk): 124 | 125 | shared_cab_group = CabGroup.query.filter_by(id=pk).first() 126 | user = User.query.filter_by(email=session["user"]).first() 127 | 128 | my_booking = Booking.query.filter_by(group=pk,user=user.id).first() 129 | DROP = my_booking.destination 130 | 131 | if shared_cab_group == None: 132 | return "404 page not found \n group does not exist" 133 | 134 | bookings = shared_cab_group.bookings 135 | 136 | 137 | return render_template( 138 | "detail-group.html", 139 | user=session["user"], 140 | grp_bookings = bookings, 141 | pk=pk, 142 | MAPS_APIKEY = maps_apikey, 143 | SOURCE = SOURCE, 144 | DROP = DROP 145 | ) 146 | 147 | 148 | @views.route("/chat/",methods=["GET"]) 149 | @is_authenticated 150 | def chat(pk): 151 | 152 | return render_template( 153 | 'chat.html', 154 | room=pk, 155 | user = session["user"] 156 | ) 157 | 158 | 159 | @views.route("/booking-payment/") 160 | @cross_origin() 161 | def booking_payment(booking_hash): 162 | 163 | booking = Booking.query.filter_by(booking_hash=booking_hash).first() 164 | if booking==None: 165 | return make_response("FAILED",404) 166 | 167 | if booking.status!=2: 168 | 169 | booking.status = 2 170 | db.session.add(booking) 171 | db.session.commit() 172 | 173 | 174 | return make_response("SUCCESS",200) -------------------------------------------------------------------------------- /contract/BookingChain.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.7; 4 | 5 | contract BookingChain{ 6 | 7 | mapping(string => uint) central; 8 | address owner; 9 | string secretKey; 10 | 11 | constructor(){ 12 | owner = msg.sender; 13 | } 14 | 15 | function setSecretKey(string memory _secretKey) public { 16 | require(owner==msg.sender,"Insufficient Permission"); 17 | secretKey = _secretKey; 18 | } 19 | 20 | function pay(string memory bookingHash) public payable{ 21 | central[bookingHash] = msg.value; 22 | } 23 | 24 | function getTotalBalance() public view returns(uint){ 25 | require(owner==msg.sender,"Insufficient Permission"); 26 | return address(this).balance; 27 | } 28 | 29 | function getBooking(string memory bookingHash) public view returns(uint){ 30 | return central[bookingHash]; 31 | } 32 | 33 | function transferFunds(string memory _secretkey,address transferTo) public{ 34 | require( 35 | keccak256(bytes(secretKey))==keccak256(bytes(_secretkey)), 36 | "Invalid Key" 37 | ); 38 | payable(transferTo).transfer(address(this).balance); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.10" 2 | 3 | services: 4 | backend: 5 | build: . 6 | restart: on-failure 7 | command: python3 server.py 8 | volumes: 9 | - .:/code 10 | ports: 11 | - "5000:5000" 12 | -------------------------------------------------------------------------------- /globals.py: -------------------------------------------------------------------------------- 1 | import googlemaps 2 | import os 3 | from flask_sqlalchemy import SQLAlchemy 4 | from dotenv import load_dotenv 5 | from flask_migrate import Migrate 6 | 7 | load_dotenv() 8 | 9 | STATIC_URI = os.path.join(os.getcwd(),"static") 10 | TEMPLATES_URI = os.path.join(os.getcwd(),"templates") 11 | DB_NAME = "database.db" 12 | UPLOAD_FOLDER = "static/images" 13 | SECRET_KEY = os.getenv("SECRET_KEY",None) 14 | SOURCE = os.getenv("ORG_SOURCE",None) 15 | maps_apikey = os.getenv("GOOGLE_MAPS_APIKEY",None) 16 | 17 | if SOURCE == None: 18 | print("ORG_SOURCE is required in .env") 19 | 20 | if SECRET_KEY == None: 21 | print("Secret key is required in .env") 22 | os._exit(0) 23 | 24 | 25 | if maps_apikey == None: 26 | print("Missing google maps api key in .env") 27 | os._exit(0) 28 | 29 | gmaps = googlemaps.Client(key=maps_apikey) 30 | 31 | db = SQLAlchemy() 32 | migrate = Migrate() -------------------------------------------------------------------------------- /migrations/README: -------------------------------------------------------------------------------- 1 | Single-database configuration for Flask. 2 | -------------------------------------------------------------------------------- /migrations/alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # template used to generate migration files 5 | # file_template = %%(rev)s_%%(slug)s 6 | 7 | # set to 'true' to run the environment during 8 | # the 'revision' command, regardless of autogenerate 9 | # revision_environment = false 10 | 11 | 12 | # Logging configuration 13 | [loggers] 14 | keys = root,sqlalchemy,alembic,flask_migrate 15 | 16 | [handlers] 17 | keys = console 18 | 19 | [formatters] 20 | keys = generic 21 | 22 | [logger_root] 23 | level = WARN 24 | handlers = console 25 | qualname = 26 | 27 | [logger_sqlalchemy] 28 | level = WARN 29 | handlers = 30 | qualname = sqlalchemy.engine 31 | 32 | [logger_alembic] 33 | level = INFO 34 | handlers = 35 | qualname = alembic 36 | 37 | [logger_flask_migrate] 38 | level = INFO 39 | handlers = 40 | qualname = flask_migrate 41 | 42 | [handler_console] 43 | class = StreamHandler 44 | args = (sys.stderr,) 45 | level = NOTSET 46 | formatter = generic 47 | 48 | [formatter_generic] 49 | format = %(levelname)-5.5s [%(name)s] %(message)s 50 | datefmt = %H:%M:%S 51 | -------------------------------------------------------------------------------- /migrations/env.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | 3 | import logging 4 | from logging.config import fileConfig 5 | 6 | from flask import current_app 7 | 8 | from alembic import context 9 | 10 | # this is the Alembic Config object, which provides 11 | # access to the values within the .ini file in use. 12 | config = context.config 13 | 14 | # Interpret the config file for Python logging. 15 | # This line sets up loggers basically. 16 | fileConfig(config.config_file_name) 17 | logger = logging.getLogger('alembic.env') 18 | 19 | # add your model's MetaData object here 20 | # for 'autogenerate' support 21 | # from myapp import mymodel 22 | # target_metadata = mymodel.Base.metadata 23 | config.set_main_option( 24 | 'sqlalchemy.url', 25 | str(current_app.extensions['migrate'].db.get_engine().url).replace( 26 | '%', '%%')) 27 | target_db = current_app.extensions['migrate'].db 28 | 29 | # other values from the config, defined by the needs of env.py, 30 | # can be acquired: 31 | # my_important_option = config.get_main_option("my_important_option") 32 | # ... etc. 33 | 34 | 35 | def get_metadata(): 36 | if hasattr(target_db, 'metadatas'): 37 | return target_db.metadatas[None] 38 | return target_db.metadata 39 | 40 | 41 | def run_migrations_offline(): 42 | """Run migrations in 'offline' mode. 43 | 44 | This configures the context with just a URL 45 | and not an Engine, though an Engine is acceptable 46 | here as well. By skipping the Engine creation 47 | we don't even need a DBAPI to be available. 48 | 49 | Calls to context.execute() here emit the given string to the 50 | script output. 51 | 52 | """ 53 | url = config.get_main_option("sqlalchemy.url") 54 | context.configure( 55 | url=url, target_metadata=get_metadata(), literal_binds=True 56 | ) 57 | 58 | with context.begin_transaction(): 59 | context.run_migrations() 60 | 61 | 62 | def run_migrations_online(): 63 | """Run migrations in 'online' mode. 64 | 65 | In this scenario we need to create an Engine 66 | and associate a connection with the context. 67 | 68 | """ 69 | 70 | # this callback is used to prevent an auto-migration from being generated 71 | # when there are no changes to the schema 72 | # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html 73 | def process_revision_directives(context, revision, directives): 74 | if getattr(config.cmd_opts, 'autogenerate', False): 75 | script = directives[0] 76 | if script.upgrade_ops.is_empty(): 77 | directives[:] = [] 78 | logger.info('No changes in schema detected.') 79 | 80 | connectable = current_app.extensions['migrate'].db.get_engine() 81 | 82 | with connectable.connect() as connection: 83 | context.configure( 84 | connection=connection, 85 | target_metadata=get_metadata(), 86 | process_revision_directives=process_revision_directives, 87 | **current_app.extensions['migrate'].configure_args 88 | ) 89 | 90 | with context.begin_transaction(): 91 | context.run_migrations() 92 | 93 | 94 | if context.is_offline_mode(): 95 | run_migrations_offline() 96 | else: 97 | run_migrations_online() 98 | -------------------------------------------------------------------------------- /migrations/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /nginx/conf.d/nginx.conf: -------------------------------------------------------------------------------- 1 | # first we declare our upstream server, which is our Gunicorn application 2 | upstream g_server { 3 | server backend:8000; 4 | } 5 | 6 | server { 7 | listen 443 ssl; 8 | server_name localhost; 9 | location / { 10 | # everything is passed to Gunicorn 11 | proxy_pass http://g_server; 12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 13 | proxy_set_header Host $host; 14 | proxy_redirect off; 15 | } 16 | 17 | } 18 | # now we declare our main server 19 | server { 20 | 21 | listen 80; 22 | server_name localhost; 23 | 24 | location / { 25 | # everything is passed to Gunicorn 26 | proxy_pass http://g_server; 27 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 28 | proxy_set_header Host $host; 29 | proxy_redirect off; 30 | } 31 | 32 | 33 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.9.0 2 | aiosignal==1.3.1 3 | alembic==1.8.1 4 | async-timeout==4.0.2 5 | attrs==22.1.0 6 | base58==2.1.1 7 | bidict==0.22.0 8 | bitarray==2.6.0 9 | blinker==1.5 10 | certifi==2022.9.24 11 | charset-normalizer==2.1.1 12 | click==8.1.3 13 | cytoolz==0.12.0 14 | dnspython==2.2.1 15 | email-validator==1.3.0 16 | eth-abi==4.2.0 17 | eth-account==0.5.9 18 | eth-hash==0.5.1 19 | eth-keyfile==0.5.1 20 | eth-keys==0.3.4 21 | eth-rlp==0.2.1 22 | eth-typing==2.3.0 23 | eth-utils==1.9.5 24 | eventlet==0.33.1 25 | exceptiongroup==1.0.1 26 | Flask==2.3.2 27 | Flask-Cors==3.0.10 28 | Flask-Mail==0.9.1 29 | Flask-Migrate==4.0.0 30 | Flask-SocketIO==5.3.1 31 | Flask-SQLAlchemy==3.0.2 32 | Flask-WTF==1.0.1 33 | frozenlist==1.3.3 34 | gevent==22.10.2 35 | gevent-websocket==0.10.1 36 | googlemaps==4.7.0 37 | greenlet==2.0.1 38 | hexbytes==0.3.0 39 | idna==3.4 40 | iniconfig==1.1.1 41 | ipfshttpclient==0.8.0a2 42 | itsdangerous==2.1.2 43 | Jinja2==3.1.3 44 | jsonschema==4.17.3 45 | lru-dict==1.1.8 46 | Mako==1.2.4 47 | MarkupSafe==2.1.1 48 | multiaddr==0.0.9 49 | multidict==6.0.3 50 | netaddr==0.8.0 51 | packaging==21.3 52 | parsimonious==0.8.1 53 | pluggy==1.0.0 54 | protobuf==3.19.5 55 | pycryptodome==3.19.1 56 | PyJWT==2.6.0 57 | pyparsing==3.0.9 58 | pyrsistent==0.19.2 59 | pytest==7.2.0 60 | python-dotenv==0.21.0 61 | python-engineio==4.3.4 62 | python-socketio==5.7.2 63 | requests==2.31.0 64 | rlp==2.0.1 65 | six==1.16.0 66 | SQLAlchemy==1.4.43 67 | tomli==2.0.1 68 | toolz==0.12.0 69 | urllib3==1.26.18 70 | varint==1.0.2 71 | web3==5.31.3 72 | websockets==9.1 73 | Werkzeug==2.3.8 74 | WTForms==3.0.1 75 | yarl==1.8.2 76 | zope.event==4.5.0 77 | zope.interface==5.5.1 78 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | from backend import create_app 2 | from flask_socketio import SocketIO 3 | # from flask_socketio import SocketIO, join_room, leave_room, send 4 | # from flask import session 5 | 6 | 7 | app = create_app() 8 | 9 | socketio = SocketIO(app,cors_allowed_origins="*") 10 | 11 | from backend.handlers import on_join_room,on_leave,handel_message 12 | 13 | 14 | if __name__ == '__main__': 15 | app.debug = True 16 | socketio.run(app,debug=True) -------------------------------------------------------------------------------- /static/bat/MailHandler.php: -------------------------------------------------------------------------------- 1 | Visitor: ' . $_POST["name"] . '

' . "\n"; 14 | $messageBody .= '
' . "\n"; 15 | } 16 | if($_POST['name']!='false'){ 17 | $messageBody .= '

Country: ' . $_POST["country"] . '

' . "\n"; 18 | $messageBody .= '
' . "\n"; 19 | } 20 | if($_POST['email']!='false'){ 21 | $messageBody .= '

Email Address: ' . $_POST['email'] . '

' . "\n"; 22 | $messageBody .= '
' . "\n"; 23 | }else{ 24 | $headers = ''; 25 | } 26 | if($_POST['state']!='false'){ 27 | $messageBody .= '

State: ' . $_POST['state'] . '

' . "\n"; 28 | $messageBody .= '
' . "\n"; 29 | } 30 | if($_POST['phone']!='false'){ 31 | $messageBody .= '

Phone Number: ' . $_POST['phone'] . '

' . "\n"; 32 | $messageBody .= '
' . "\n"; 33 | } 34 | if($_POST['fax']!='false'){ 35 | $messageBody .= '

Fax Number: ' . $_POST['fax'] . '

' . "\n"; 36 | $messageBody .= '
' . "\n"; 37 | } 38 | if($_POST['message']!='false'){ 39 | $messageBody .= '

Message: ' . $_POST['message'] . '

' . "\n"; 40 | } 41 | 42 | if($_POST["stripHTML"] == 'true'){ 43 | $messageBody = strip_tags($messageBody); 44 | } 45 | 46 | if($host=="" or $username=="" or $password==""){ 47 | $owner_email = $_POST["owner_email"]; 48 | $headers = 'From:' . $_POST["email"] . "\r\n" . 'Content-Type: text/plain; charset=UTF-8' . "\r\n"; 49 | $subject = 'A message from your site visitor ' . $_POST["name"]; 50 | 51 | try{ 52 | if(!mail($owner_email, $subject, $messageBody, $headers)){ 53 | throw new Exception('mail failed'); 54 | }else{ 55 | echo 'mail sent'; 56 | } 57 | }catch(Exception $e){ 58 | echo $e->getMessage() ."\n"; 59 | } 60 | }else{ 61 | require_once 'Mail.php'; 62 | 63 | $to = $_POST["owner_email"]; 64 | $subject = 'A message from your site visitor ' . $_POST["name"]; 65 | $headers = array ( 66 | 'From' => 'From:' . $_POST["email"] . "\r\n" . 'Content-Type: text/plain; charset=UTF-8' . "\r\n", 67 | 'To' => $to, 68 | 'Subject' => $subject); 69 | 70 | $smtp = Mail::factory( 71 | 'smtp', 72 | array ( 73 | 'host' => $host, 74 | 'port' => $port, 75 | 'auth' => true, 76 | 'username' => $username, 77 | 'password' => $password)); 78 | 79 | $mail = $smtp->send($to, $headers, $messageBody); 80 | 81 | try{ 82 | if(PEAR::isError($mail)){ 83 | echo $mail->getMessage(); 84 | }else{ 85 | echo 'mail sent'; 86 | } 87 | }catch(Exception $mail){ 88 | echo $mail->getMessage() ."\n"; 89 | } 90 | } 91 | ?> -------------------------------------------------------------------------------- /static/booking/booking.php: -------------------------------------------------------------------------------- 1 | $value) { 10 | echo "$key".': '."$value".'&'; 11 | if (($value != 'nope') && ($key != 'owner_email') && ($key != 'sender')) { 12 | $messageBody .="$key" . ': '."$value" . "\n\n"; 13 | } 14 | } 15 | 16 | try{ 17 | echo $_POST['Email']; 18 | echo $subject; 19 | echo $messageBody; 20 | 21 | if(!mail($ownerEmail, $subject, $messageBody, $headers)){ 22 | throw new Exception('mail failed'); 23 | }else{ 24 | echo 'mail sent'; 25 | } 26 | }catch(Exception $e){ 27 | echo $e->getMessage() ."\n"; 28 | } 29 | ?> -------------------------------------------------------------------------------- /static/booking/css/booking.css: -------------------------------------------------------------------------------- 1 | @import '../font/font-awesome.css'; 2 | /* CSS for jquery.fancyform.js */ 3 | /*custom mixins */ 4 | /*end custom mixins */ 5 | /* Control Holder */ 6 | 7 | #bookingForm { 8 | padding-right: 36px; 9 | font-family: 'Open Sans', sans-serif; 10 | } 11 | 12 | .tmInput { 13 | position: relative; 14 | } 15 | 16 | .mr0 { 17 | margin-right: 0; 18 | } 19 | 20 | .tmTextarea { 21 | padding-top: 12px; 22 | } 23 | 24 | .fl1 { 25 | width: 193px; 26 | float: left; 27 | } 28 | 29 | .fl1.fl2 { 30 | top: 33px; 31 | } 32 | 33 | .fl1+.fl1 { 34 | margin-left: 47px; 35 | } 36 | 37 | .fl1 em { 38 | font-style: normal; 39 | padding-top: 12px; 40 | display: block; 41 | float: left; 42 | padding-left: 12px; 43 | } 44 | 45 | .fl1 em +div { 46 | float: right; 47 | } 48 | 49 | .tmInput { 50 | width: 100%; 51 | } 52 | 53 | 54 | .height1 { 55 | height: 44px !important; 56 | } 57 | 58 | .fl1 em +.controlHolder { 59 | margin-bottom: 0; 60 | } 61 | 62 | .tmSelect { 63 | margin-bottom: 8px !important; 64 | } 65 | 66 | 67 | .tmInput { 68 | margin-right: 47px; 69 | } 70 | 71 | #bookingForm { 72 | position: relative; 73 | display: block; 74 | padding-top: 5px; 75 | color: #737272; 76 | font: 14px/20px 'Open Sans', sans-serif; 77 | } 78 | 79 | #bookingForm input, 80 | #bookingForm textarea { 81 | outline: none; 82 | -webkit-box-sizing: border-box; 83 | -moz-box-sizing: border-box; 84 | box-sizing: border-box; 85 | 86 | border: 1px solid #f1f1f1; 87 | color: #737272; 88 | background: #f0f3f5; 89 | padding: 5px 12px; 90 | width: 100%; 91 | font: 14px/20px 'Open Sans', sans-serif; 92 | height: 30px; 93 | 94 | } 95 | 96 | #bookingForm textarea { 97 | resize: none; 98 | padding-top: 10px !important; 99 | color: #737272; 100 | font: 14px/20px 'Open Sans', sans-serif; 101 | height: 143px !important; 102 | -webkit-box-sizing: border-box; 103 | -moz-box-sizing: border-box; 104 | box-sizing: border-box; 105 | 106 | } 107 | 108 | 109 | 110 | #bookingForm input::-webkit-input-placeholder { 111 | color: #737272; 112 | } 113 | 114 | input::-webkit-input-placeholder , 115 | textarea::-webkit-input-placeholder 116 | {color:#737272;} 117 | 118 | input::-moz-placeholder, 119 | textarea::-moz-placeholder 120 | {color:#737272;} 121 | 122 | #bookingForm input:focus, 123 | #bookingForm textarea:focus { 124 | background: #fff; 125 | } 126 | 127 | #bookingForm a.btn { 128 | } 129 | #bookingForm a.btn:hover { 130 | } 131 | .controlHolder { 132 | position: relative; 133 | margin-bottom: 13px; 134 | } 135 | /* Messages */ 136 | .error-message { 137 | position: absolute; 138 | top: 31px; 139 | white-space: nowrap; 140 | right: 0px; 141 | font-weight: normal; 142 | text-align: right; 143 | font-size: 10px; 144 | line-height: 1em; 145 | color: gray; 146 | z-index: 4; 147 | color: #fe5353; 148 | } 149 | .success-message { 150 | position: relative; 151 | text-align: left; 152 | color: gray; 153 | margin: 5px 0px; 154 | color: #F3AA29; 155 | } 156 | /* transformSelect CSS */ 157 | /* 1st type of select */ 158 | .tmSelect, 159 | .tmSelect2 { 160 | clear: both; 161 | width: 100%; 162 | margin: 0px; 163 | } 164 | .tmSelect li, 165 | .tmSelect2 li { 166 | position: relative; 167 | list-style: none; 168 | 169 | } 170 | .tmSelect span, 171 | .tmSelect2 span, 172 | .tmSelect input[type=text], 173 | .tmSelect2 input[type=text] { 174 | position: relative; 175 | cursor: pointer; 176 | display: block; 177 | left: 0; 178 | top: 0; 179 | margin: 0; 180 | } 181 | .tmSelect:after, 182 | .tmSelect2:after { 183 | content: '\f002'; 184 | position: absolute; 185 | top: 8px; 186 | right: 9px; 187 | font: normal normal 18px 'FontAwesome'; 188 | color: #ccc; 189 | z-index: 4; 190 | } 191 | .tmSelect.auto, 192 | .tmSelect2.auto { 193 | cursor: pointer; 194 | padding: 0; 195 | margin: 6px 0 20px 0; 196 | border: 1px #f1f1f1 solid; 197 | color: #737272; 198 | background: #f0f3f5; 199 | font: 14px/20px 'Open Sans', sans-serif; 200 | width: 95px; 201 | height: 30px; 202 | float: right; 203 | -webkit-box-sizing: border-box; 204 | -moz-box-sizing: border-box; 205 | box-sizing: border-box; 206 | } 207 | .tmSelect.auto span, 208 | .tmSelect2.auto span { 209 | background: transparent; 210 | } 211 | .tmSelect.auto:focus, 212 | .tmSelect2.auto:focus { 213 | background: #fff; 214 | } 215 | .tmSelect.auto ul, 216 | .tmSelect2.auto ul { 217 | margin: 0px 0 0; 218 | float: right; 219 | -webkit-box-sizing: border-box; 220 | -moz-box-sizing: border-box; 221 | box-sizing: border-box; 222 | width: 55px; 223 | } 224 | .tmSelect.auto > li:first-child > span, 225 | .tmSelect2.auto > li:first-child > span { 226 | padding: 4px 12px 6px; 227 | color: #737272; 228 | width: 100%; 229 | z-index: 10; 230 | position: relative; 231 | -webkit-box-sizing: border-box; 232 | -moz-box-sizing: border-box; 233 | box-sizing: border-box; 234 | } 235 | .tmSelect ul, 236 | .tmSelect2 ul, 237 | .tmSelect .transformSelectDropdown, 238 | .tmSelect2 .transformSelectDropdown { 239 | position: absolute; 240 | width: 100%; 241 | max-height: 210px; 242 | padding: 0px 0px; 243 | top: 29px; 244 | margin: 0px; 245 | right: 0; 246 | border: 1px #ccc solid; 247 | color: #737272; 248 | min-height: 65px; 249 | background: #fff; 250 | font: 12px/18px Arial, sans-serif; 251 | -webkit-box-sizing: border-box; 252 | -moz-box-sizing: border-box; 253 | box-sizing: border-box; 254 | box-shadow: none; 255 | z-index: 999; 256 | } 257 | .tmSelect ul:focus, 258 | .tmSelect2 ul:focus, 259 | .tmSelect .transformSelectDropdown:focus, 260 | .tmSelect2 .transformSelectDropdown:focus { 261 | background: #fff; 262 | } 263 | .tmSelect ul span, 264 | .tmSelect2 ul span, 265 | .tmSelect .transformSelectDropdown span, 266 | .tmSelect2 .transformSelectDropdown span { 267 | border: 0; 268 | color: #000; 269 | padding: 0px 9px; 270 | line-height: 17px; 271 | } 272 | .tmSelect ul span:hover, 273 | .tmSelect2 ul span:hover, 274 | .tmSelect .transformSelectDropdown span:hover, 275 | .tmSelect2 .transformSelectDropdown span:hover { 276 | background: #d2dae0; 277 | } 278 | .tmSelect ul li input[type=checkbox], 279 | .tmSelect2 ul li input[type=checkbox] { 280 | position: relative; 281 | top: 2px; 282 | margin: 0 5px 0 0; 283 | cursor: pointer; 284 | } 285 | /* 2nd type of select */ 286 | .tmSelect2:after { 287 | content: ''; 288 | background-color: #d2dae0; 289 | width: 23px; 290 | height: 22px; 291 | text-align: center; 292 | color: #adaeaf; 293 | font-size: 14px; 294 | line-height: 25px; 295 | right: 4px; 296 | margin-top: 2px; 297 | } 298 | /* Radio */ 299 | .trans-element-radio { 300 | display: inline-block; 301 | display: block; 302 | zoom: 1; 303 | width: 15px; 304 | height: 15px; 305 | cursor: pointer; 306 | } 307 | .tmRadio { 308 | padding-left: 0; 309 | } 310 | .tmRadio p { 311 | padding-bottom: 0; 312 | margin-bottom: 0; 313 | padding-top: 0px; 314 | position: relative; 315 | top: -6px; 316 | } 317 | .tmRadio p { 318 | padding-bottom: 0; 319 | margin-bottom: 3px; 320 | padding-left: 30px; 321 | } 322 | .tmRadio input { 323 | margin-right: 5px; 324 | } 325 | .tmRadio .unchecked, 326 | .tmRadio .checked { 327 | position: relative; 328 | cursor: pointer; 329 | margin-right: 5px; 330 | } 331 | 332 | .tmRadio strong { 333 | margin-left: 30px; 334 | } 335 | 336 | .tmRadio { 337 | margin-left: -30px !important; 338 | } 339 | .tmRadio .unchecked:after, 340 | .tmRadio .checked:after { 341 | content: '\f10c'; 342 | position: relative; 343 | top: 1px; 344 | font: normal normal 20px 'FontAwesome'; 345 | color: #adaeaf; 346 | } 347 | .tmRadio .checked:after { 348 | content: '\f05d'; 349 | color: #98a6b3; 350 | } 351 | /* Checkbox */ 352 | .trans-element-checkbox { 353 | cursor: pointer; 354 | zoom: 1; 355 | } 356 | .trans-element-checkbox span { 357 | padding-left: 40px; 358 | 359 | } 360 | .trans-element-checkbox.checked:after { 361 | content: '\f046'; 362 | } 363 | .trans-element-checkbox:after { 364 | content: '\f096'; 365 | position: relative; 366 | display: inline-block; 367 | top: 2px; 368 | width: 17px; 369 | font: normal normal 18px 'FontAwesome'; 370 | color: #ccc; 371 | } 372 | .trans-element-checkbox.unchecked:after { 373 | content: '\f096'; 374 | } 375 | .tmCheckbox, 376 | .tmRadio { 377 | margin-left: 0; 378 | padding-left: 0; 379 | padding: 0; 380 | } 381 | .tmCheckbox span, 382 | .tmRadio span { 383 | position: relative; 384 | margin-right: 10px; 385 | top: 1px; 386 | } 387 | /* Datepicker */ 388 | .tmDatepicker { 389 | position: relative; 390 | margin-bottom: 20px; 391 | } 392 | 393 | #bookingForm>strong { 394 | display: block; 395 | font-weight: normal; 396 | float: left; 397 | padding-top: 7px; 398 | } 399 | 400 | 401 | #bookingForm>strong+.controlHolder { 402 | width: 336px; 403 | float: right; 404 | padding-top: 1px; 405 | } 406 | 407 | .tmDatepicker { 408 | display: block; 409 | margin-bottom: 0; 410 | } 411 | 412 | .tmDatepicker:after { 413 | content: '\f073'; 414 | position: absolute; 415 | bottom: 5px; 416 | right: 23px; 417 | font: normal normal 20px/20px 'FontAwesome'; 418 | color: #98a6b3; 419 | z-index: 4; 420 | cursor: text; 421 | } 422 | .ui-datepicker { 423 | padding: 10px; 424 | width: 300px; 425 | font-size: 13px; 426 | display: none; 427 | z-index: 100 !important; 428 | -webkit-box-sizing: border-box; 429 | -moz-box-sizing: border-box; 430 | box-sizing: border-box; 431 | -webkit-border-radius: 4px; 432 | -moz-border-radius: 4px; 433 | border: 1px #ccc solid; 434 | color: #737272; 435 | background: #F0F3F5; 436 | } 437 | .ui-datepicker:focus { 438 | background: #fff; 439 | } 440 | .ui-datepicker a { 441 | color: #777; 442 | } 443 | .ui-datepicker a:hover { 444 | color: #000; 445 | text-decoration: none; 446 | } 447 | .ui-datepicker-prev, 448 | .ui-datepicker-next { 449 | cursor: pointer; 450 | float: left; 451 | } 452 | .ui-datepicker-next { 453 | float: right; 454 | } 455 | .ui-datepicker-title { 456 | text-align: center; 457 | } 458 | .ui-datepicker-calendar { 459 | margin: 10px 11px; 460 | } 461 | .ui-datepicker-calendar td { 462 | padding: 1px 10px; 463 | text-align: center; 464 | } 465 | .ui-datepicker-calendar .ui-datepicker-current-day, 466 | .ui-datepicker-calendar .ui-datepicker-today { 467 | -webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2); 468 | -moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2); 469 | box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2); 470 | -webkit-border-radius: 4px; 471 | -moz-border-radius: 4px; 472 | border-radius: 4px; 473 | padding: 6px 15px; 474 | border: 1px #ccc solid; 475 | background: #f5f5f5; 476 | color: #000; 477 | font-weight: normal; 478 | padding: 3px; 479 | } 480 | .ui-datepicker-calendar .ui-datepicker-current-day:hover, 481 | .ui-datepicker-calendar .ui-datepicker-today:hover { 482 | background: #efefef; 483 | } 484 | .ui-datepicker-calendar .ui-datepicker-today { 485 | border-color: #fff; 486 | } 487 | button.ui-state-default { 488 | border: none; 489 | padding: 3px 7px; 490 | font: 12px/18px Arial, sans-serif; 491 | -webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2); 492 | -moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2); 493 | box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2); 494 | -webkit-border-radius: 4px; 495 | -moz-border-radius: 4px; 496 | border-radius: 4px; 497 | padding: 6px 15px; 498 | border: 1px #ccc solid; 499 | background: #f5f5f5; 500 | color: #000; 501 | font-weight: normal; 502 | } 503 | button.ui-state-default:hover { 504 | background: #efefef; 505 | } 506 | .ui-datepicker-close { 507 | float: right; 508 | } 509 | .clearfix { 510 | *zoom: 1; 511 | } 512 | .clearfix:before, 513 | .clearfix:after { 514 | display: table; 515 | content: ""; 516 | line-height: 0; 517 | } 518 | .clearfix:after { 519 | clear: both; 520 | } 521 | .hide-text { 522 | font: 0/0 a; 523 | color: transparent; 524 | text-shadow: none; 525 | background-color: transparent; 526 | border: 0; 527 | } 528 | 529 | #map-canvas { 530 | height: 100%; 531 | width: 100%; 532 | } 533 | -------------------------------------------------------------------------------- /static/booking/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/booking/font/FontAwesome.otf -------------------------------------------------------------------------------- /static/booking/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/booking/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/booking/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/booking/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/booking/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/booking/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/booking/font/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/booking/font/icomoon.eot -------------------------------------------------------------------------------- /static/booking/font/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/booking/font/icomoon.ttf -------------------------------------------------------------------------------- /static/booking/font/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/booking/font/icomoon.woff -------------------------------------------------------------------------------- /static/booking/js/jquery.placeholder.js: -------------------------------------------------------------------------------- 1 | /*! http://mths.be/placeholder v2.0.7 by @mathias */ 2 | ;(function(window, document, $) { 3 | 4 | // Opera Mini v7 doesn’t support placeholder although its DOM seems to indicate so 5 | var isOperaMini = Object.prototype.toString.call(window.operamini) == '[object OperaMini]'; 6 | var isInputSupported = 'placeholder' in document.createElement('input') && !isOperaMini; 7 | var isTextareaSupported = 'placeholder' in document.createElement('textarea') && !isOperaMini; 8 | var prototype = $.fn; 9 | var valHooks = $.valHooks; 10 | var propHooks = $.propHooks; 11 | var hooks; 12 | var placeholder; 13 | 14 | if (isInputSupported && isTextareaSupported) { 15 | 16 | placeholder = prototype.placeholder = function() { 17 | return this; 18 | }; 19 | 20 | placeholder.input = placeholder.textarea = true; 21 | 22 | } else { 23 | 24 | placeholder = prototype.placeholder = function() { 25 | var $this = this; 26 | $this 27 | .filter((isInputSupported ? 'textarea' : ':input') + '[placeholder]') 28 | .not('.placeholder') 29 | .bind({ 30 | 'focus.placeholder': clearPlaceholder, 31 | 'blur.placeholder': setPlaceholder 32 | }) 33 | .data('placeholder-enabled', true) 34 | .trigger('blur.placeholder'); 35 | return $this; 36 | }; 37 | 38 | placeholder.input = isInputSupported; 39 | placeholder.textarea = isTextareaSupported; 40 | 41 | hooks = { 42 | 'get': function(element) { 43 | var $element = $(element); 44 | 45 | var $passwordInput = $element.data('placeholder-password'); 46 | if ($passwordInput) { 47 | return $passwordInput[0].value; 48 | } 49 | 50 | return $element.data('placeholder-enabled') && $element.hasClass('placeholder') ? '' : element.value; 51 | }, 52 | 'set': function(element, value) { 53 | var $element = $(element); 54 | 55 | var $passwordInput = $element.data('placeholder-password'); 56 | if ($passwordInput) { 57 | return $passwordInput[0].value = value; 58 | } 59 | 60 | if (!$element.data('placeholder-enabled')) { 61 | return element.value = value; 62 | } 63 | if (value == '') { 64 | element.value = value; 65 | // Issue #56: Setting the placeholder causes problems if the element continues to have focus. 66 | if (element != safeActiveElement()) { 67 | // We can't use `triggerHandler` here because of dummy text/password inputs :( 68 | setPlaceholder.call(element); 69 | } 70 | } else if ($element.hasClass('placeholder')) { 71 | clearPlaceholder.call(element, true, value) || (element.value = value); 72 | } else { 73 | element.value = value; 74 | } 75 | // `set` can not return `undefined`; see http://jsapi.info/jquery/1.7.1/val#L2363 76 | return $element; 77 | } 78 | }; 79 | 80 | if (!isInputSupported) { 81 | valHooks.input = hooks; 82 | propHooks.value = hooks; 83 | } 84 | if (!isTextareaSupported) { 85 | valHooks.textarea = hooks; 86 | propHooks.value = hooks; 87 | } 88 | 89 | $(function() { 90 | // Look for forms 91 | $(document).delegate('form', 'submit.placeholder', function() { 92 | // Clear the placeholder values so they don't get submitted 93 | var $inputs = $('.placeholder', this).each(clearPlaceholder); 94 | setTimeout(function() { 95 | $inputs.each(setPlaceholder); 96 | }, 10); 97 | }); 98 | }); 99 | 100 | // Clear placeholder values upon page reload 101 | $(window).bind('beforeunload.placeholder', function() { 102 | $('.placeholder').each(function() { 103 | this.value = ''; 104 | }); 105 | }); 106 | 107 | } 108 | 109 | function args(elem) { 110 | // Return an object of element attributes 111 | var newAttrs = {}; 112 | var rinlinejQuery = /^jQuery\d+$/; 113 | $.each(elem.attributes, function(i, attr) { 114 | if (attr.specified && !rinlinejQuery.test(attr.name)) { 115 | newAttrs[attr.name] = attr.value; 116 | } 117 | }); 118 | return newAttrs; 119 | } 120 | 121 | function clearPlaceholder(event, value) { 122 | var input = this; 123 | var $input = $(input); 124 | if (input.value == $input.attr('placeholder') && $input.hasClass('placeholder')) { 125 | if ($input.data('placeholder-password')) { 126 | $input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id')); 127 | // If `clearPlaceholder` was called from `$.valHooks.input.set` 128 | if (event === true) { 129 | return $input[0].value = value; 130 | } 131 | $input.focus(); 132 | } else { 133 | input.value = ''; 134 | $input.removeClass('placeholder'); 135 | input == safeActiveElement() && input.select(); 136 | } 137 | } 138 | } 139 | 140 | function setPlaceholder() { 141 | var $replacement; 142 | var input = this; 143 | var $input = $(input); 144 | var id = this.id; 145 | if (input.value == '') { 146 | if (input.type == 'password') { 147 | if (!$input.data('placeholder-textinput')) { 148 | try { 149 | $replacement = $input.clone().attr({ 'type': 'text' }); 150 | } catch(e) { 151 | $replacement = $('').attr($.extend(args(this), { 'type': 'text' })); 152 | } 153 | $replacement 154 | .removeAttr('name') 155 | .data({ 156 | 'placeholder-password': $input, 157 | 'placeholder-id': id 158 | }) 159 | .bind('focus.placeholder', clearPlaceholder); 160 | $input 161 | .data({ 162 | 'placeholder-textinput': $replacement, 163 | 'placeholder-id': id 164 | }) 165 | .before($replacement); 166 | } 167 | $input = $input.removeAttr('id').hide().prev().attr('id', id).show(); 168 | // Note: `$input[0] != input` now! 169 | } 170 | $input.addClass('placeholder'); 171 | $input[0].value = $input.attr('placeholder'); 172 | } else { 173 | $input.removeClass('placeholder'); 174 | } 175 | } 176 | 177 | function safeActiveElement() { 178 | // Avoid IE9 `document.activeElement` of death 179 | // https://github.com/mathiasbynens/jquery-placeholder/pull/99 180 | try { 181 | return document.activeElement; 182 | } catch (err) {} 183 | } 184 | 185 | }(this, document, jQuery)); 186 | -------------------------------------------------------------------------------- /static/booking/less/booking.less: -------------------------------------------------------------------------------- 1 | @import '../font/font-awesome.css'; 2 | /* CSS for jquery.fancyform.js */ 3 | 4 | /*custom mixins */ 5 | .customStyle(){ 6 | .box-shadow(inset 0px 0px 10px 0px rgba(0, 0, 0, 0.2)); 7 | .box-sizing(border-box); 8 | .border-radius(4px); 9 | border: 1px #ccc solid; 10 | color: #000; 11 | background: #fff; 12 | &:focus{ 13 | background: #fff; 14 | } 15 | } 16 | .buttonStyle(){ 17 | .box-shadow(0px 0px 5px 0px rgba(0, 0, 0, 0.2)); 18 | .border-radius(4px); 19 | padding: 6px 15px; 20 | border: 1px #ccc solid; 21 | background: #f5f5f5; 22 | color: #000; 23 | font-weight: normal; 24 | &:hover { 25 | background: #efefef; 26 | } 27 | } 28 | .customFont(){ 29 | font: 12px/18px Arial, sans-serif; 30 | } 31 | .fontAwesome(){ 32 | font: normal normal 18px 'FontAwesome'; 33 | color: #ccc; 34 | } 35 | /*end custom mixins */ 36 | /* Control Holder */ 37 | #bookingForm { 38 | position: relative; 39 | width: 100%; 40 | margin: 30px 0; 41 | .customFont(); 42 | input, 43 | textarea{ 44 | outline: none; 45 | .customStyle(); 46 | padding: 8px 10px; 47 | line-height: 15px; 48 | .size(34px,100%); 49 | } 50 | textarea { 51 | min-height: 200px; 52 | resize: none; 53 | .customFont(); 54 | } 55 | a.btn{ 56 | .buttonStyle(); 57 | } 58 | } 59 | .controlHolder{ 60 | position: relative; 61 | margin-bottom: 10px; 62 | } 63 | /* Messages */ 64 | .error-message{ 65 | position: absolute; 66 | top: 4px; 67 | right: 2px; 68 | font-weight: normal; 69 | text-align: right; 70 | width: 100%; 71 | font-size: 10px; 72 | line-height: 1em; 73 | color: gray; 74 | z-index: 4; 75 | color: #fe5353; 76 | } 77 | .success-message{ 78 | position: relative; 79 | text-align: left; 80 | color: gray; 81 | margin: 5px 0px; 82 | color: #28a1fe; 83 | } 84 | /* transformSelect CSS */ 85 | /* 1st type of select */ 86 | .tmSelect, .tmSelect2 { 87 | clear: both; 88 | width: 100%; 89 | margin: 0px; 90 | li{ 91 | position: relative; 92 | list-style: none; 93 | } 94 | span, input[type=text] { 95 | position: relative; 96 | cursor: pointer; 97 | display: block; 98 | left: 0; 99 | top: 0; 100 | margin: 0; 101 | } 102 | &:after{ 103 | content: '\f002'; 104 | position: absolute; 105 | top: 8px; 106 | right: 9px; 107 | .fontAwesome(); 108 | z-index: 4; 109 | } 110 | &.auto{ 111 | cursor: pointer; 112 | span { 113 | background: transparent; 114 | } 115 | padding: 0; 116 | margin: 0 0 20px 0; 117 | line-height: 20px; 118 | .customStyle(); 119 | .customFont(); 120 | .box-sizing(border-box); 121 | ul{ 122 | margin: 1px 0 0; 123 | .box-sizing(border-box); 124 | width: 100%; 125 | background: #f9f9f9; 126 | } 127 | >li{ 128 | &:first-child>span{ 129 | padding: 7px 12px; 130 | width: 100%; 131 | .box-sizing(border-box); 132 | } 133 | } 134 | } 135 | ul, .transformSelectDropdown{ 136 | position: absolute; 137 | width: 100%; 138 | max-height: 210px; 139 | padding: 7px 0px; 140 | margin: 0px; 141 | .customStyle(); 142 | .customFont(); 143 | border-top: none; 144 | border-top-left-radius: 0px; 145 | border-top-right-radius: 0px; 146 | .box-sizing(border-box); 147 | box-shadow: none; 148 | background: #f9f9f9; 149 | z-index: 10; 150 | span { 151 | border: 0; 152 | color: #000; 153 | padding: 5px 13px; 154 | &:hover{ 155 | background: #ccc; 156 | } 157 | } 158 | } 159 | ul li input[type=checkbox] { 160 | position: relative; 161 | top: 2px; 162 | margin: 0 5px 0 0; 163 | cursor: pointer; 164 | } 165 | } 166 | /* 2nd type of select */ 167 | .tmSelect2{ 168 | &:after{ 169 | content: '\f0ab'; 170 | } 171 | } 172 | /* Radio */ 173 | .trans-element-radio{ 174 | display: inline-block; 175 | display: block; 176 | zoom: 1; 177 | width: 15px; 178 | height: 15px; 179 | cursor: pointer; 180 | } 181 | .tmRadio{ 182 | padding-left: 0; 183 | p{ 184 | padding-bottom: 0; 185 | margin-bottom: 0; 186 | } 187 | p{ 188 | padding-bottom: 0; 189 | margin-bottom: 3px; 190 | } 191 | input{ 192 | margin-right: 5px; 193 | } 194 | .unchecked, .checked{ 195 | position: relative; 196 | cursor: pointer; 197 | margin-right: 10px; 198 | &:after{ 199 | content: '\f10c'; 200 | position: relative; 201 | top: 2px; 202 | .fontAwesome(); 203 | } 204 | } 205 | .checked{ 206 | &:after{ 207 | content: '\f05d'; 208 | } 209 | } 210 | } 211 | /* Checkbox */ 212 | .trans-element-checkbox{ 213 | cursor: pointer; 214 | zoom: 1; 215 | span{ 216 | padding-left: 40px; 217 | } 218 | &.checked{ 219 | &:after{ 220 | content: '\f046'; 221 | } 222 | } 223 | &:after{ 224 | content: '\f096'; 225 | position: relative; 226 | display: inline-block; 227 | top: 2px; 228 | width: 17px; 229 | .fontAwesome(); 230 | } 231 | &.unchecked{ 232 | &:after{ 233 | content: '\f096'; 234 | } 235 | } 236 | } 237 | .tmCheckbox, .tmRadio{ 238 | margin-left: 0; 239 | padding-left: 0; 240 | padding: 0; 241 | span{ 242 | position: relative; 243 | margin-right: 10px; 244 | } 245 | } 246 | /* Datepicker */ 247 | .tmDatepicker{ 248 | position: relative; 249 | margin-bottom: 20px; 250 | &:after{ 251 | content: '\f073'; 252 | position: absolute; 253 | top: 7px; 254 | right: 9px; 255 | .fontAwesome(); 256 | z-index: 4; 257 | } 258 | } 259 | .ui-datepicker{ 260 | padding: 10px; 261 | width: 300px; 262 | font-size: 13px; 263 | display:none; 264 | z-index: 100 !important; 265 | .customStyle(); 266 | background: #f9f9f9; 267 | a{ 268 | color: #777; 269 | &:hover{ 270 | color: #000; 271 | text-decoration: none; 272 | } 273 | } 274 | } 275 | .ui-datepicker-prev, .ui-datepicker-next{ 276 | cursor: pointer; 277 | float: left; 278 | } 279 | .ui-datepicker-next{ 280 | float: right; 281 | } 282 | .ui-datepicker-title{ 283 | text-align: center; 284 | } 285 | .ui-datepicker-calendar{ 286 | margin: 10px 11px; 287 | td{ 288 | padding: 1px 10px; 289 | text-align: center; 290 | } 291 | .ui-datepicker-current-day, .ui-datepicker-today{ 292 | .buttonStyle(); 293 | padding: 3px; 294 | } 295 | .ui-datepicker-today{ 296 | border-color: #fff; 297 | } 298 | } 299 | button.ui-state-default{ 300 | border: none; 301 | padding: 3px 7px; 302 | .customFont(); 303 | .buttonStyle(); 304 | } 305 | .ui-datepicker-close{ 306 | float: right; 307 | } 308 | 309 | @import "mixins.less"; -------------------------------------------------------------------------------- /static/css/adipoli.css: -------------------------------------------------------------------------------- 1 | .adipoli-wrapper 2 | { 3 | margin:auto; 4 | position:absolute; 5 | left: 0; 6 | right: 0; 7 | top: 0; 8 | bottom: 0; 9 | display: inline-block; 10 | } 11 | .adipoli-wrapper>img 12 | { 13 | position: absolute; 14 | z-index: 1; 15 | } 16 | .adipoli-before 17 | { 18 | position: absolute; 19 | z-index: 5; 20 | } 21 | .adipoli-after 22 | { 23 | position: absolute; 24 | z-index: 10; 25 | } 26 | .adipoli-slice { 27 | display:block; 28 | position:absolute; 29 | z-index:15; 30 | height:100%; 31 | } 32 | .adipoli-box 33 | { 34 | display:block; 35 | position:absolute; 36 | z-index:15; 37 | } -------------------------------------------------------------------------------- /static/css/camera.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /************************** 4 | * 5 | * GENERAL 6 | * 7 | **************************/ 8 | 9 | 10 | .slider_wrapper { 11 | position: relative; 12 | text-align: left; 13 | } 14 | 15 | 16 | .camera_target_content { 17 | overflow: hidden !important; 18 | 19 | } 20 | 21 | .camera_wrap { 22 | display: none; 23 | position: relative; 24 | overflow: visible !important; 25 | z-index: 0; 26 | margin-bottom: 0 !important; 27 | } 28 | 29 | 30 | .camera_wrap img { 31 | max-width: 10000px; 32 | } 33 | 34 | .camera_fakehover { 35 | height: 100%; 36 | min-height: 60px; 37 | position: relative; 38 | width: 100%; 39 | } 40 | 41 | .camera_src { 42 | display: none; 43 | } 44 | .cameraCont, .cameraContents { 45 | height: 100%; 46 | position: relative; 47 | width: 100%; 48 | z-index: 1; 49 | } 50 | .cameraSlide { 51 | bottom: 0; 52 | left: 0; 53 | position: absolute; 54 | right: 0; 55 | top: 0; 56 | width: 100%; 57 | } 58 | .cameraContent { 59 | bottom: 0; 60 | display: none; 61 | left: 0; 62 | position: absolute; 63 | right: 0; 64 | top: 0; 65 | width: 100%; 66 | } 67 | .camera_target { 68 | bottom: 0; 69 | height: 100%; 70 | left: 0; 71 | overflow: hidden; 72 | position: absolute; 73 | right: 0; 74 | text-align: left; 75 | top: 0; 76 | width: 100%; 77 | z-index: 0; 78 | } 79 | .camera_overlayer { 80 | bottom: 0; 81 | height: 100%; 82 | left: 0; 83 | overflow: hidden; 84 | position: absolute; 85 | right: 0; 86 | top: 0; 87 | width: 100%; 88 | z-index: 0; 89 | } 90 | .camera_target_content { 91 | bottom: 0; 92 | left: 0; 93 | overflow: hidden; 94 | position: absolute; 95 | right: 0; 96 | top: 0; 97 | z-index: 2; 98 | } 99 | .camera_target_content .camera_link { 100 | background: url(../images/blank.gif); 101 | display: block; 102 | height: 100%; 103 | text-decoration: none; 104 | } 105 | .camera_loader { 106 | background: #fff url(../images/camera-loader.gif) no-repeat center; 107 | background: rgba(255, 255, 255, 0.9) url(../images/camera-loader.gif) no-repeat center; 108 | border: 1px solid #ffffff; 109 | border-radius: 18px; 110 | height: 36px; 111 | left: 50%; 112 | overflow: hidden; 113 | position: absolute; 114 | margin: -18px 0 0 -18px; 115 | top: 50%; 116 | width: 36px; 117 | z-index: 3; 118 | } 119 | 120 | .camera_nav_cont { 121 | height: 65px; 122 | overflow: hidden; 123 | position: absolute; 124 | right: 9px; 125 | top: 15px; 126 | width: 120px; 127 | z-index: 4; 128 | } 129 | .camerarelative { 130 | overflow: hidden; 131 | position: relative; 132 | } 133 | .imgFake { 134 | cursor: pointer; 135 | } 136 | .camera_commands > .camera_stop { 137 | display: none; 138 | } 139 | 140 | 141 | .slide_wrapper .camera_prev{ 142 | background: url(../images/prevnext_bg.png) 0 0 repeat; 143 | width: 70px; 144 | top: 0 !important; 145 | height: auto !important; 146 | bottom: 0; 147 | left: -80px; 148 | display: block; 149 | position: absolute; 150 | opacity: 1 !important; 151 | transition: 0.5s ease; 152 | -o-transition: 0.5s ease; 153 | -webkit-transition: 0.5s ease; 154 | } 155 | 156 | .slide_wrapper .camera_prev>span { 157 | background: url(../images/prev.png) center 0 no-repeat; 158 | top: 50%; 159 | 160 | margin-top: -10px; 161 | position: absolute; 162 | display: block; 163 | height: 20px; 164 | left: 0; 165 | right: 0; 166 | } 167 | 168 | .slide_wrapper .camera_next>span { 169 | background: url(../images/next.png) center 0 no-repeat; 170 | top: 50%; 171 | margin-top: -10px; 172 | position: absolute; 173 | display: block; 174 | left: 0; 175 | right: 0; 176 | height: 20px; 177 | } 178 | 179 | 180 | 181 | .slide_wrapper .camera_next { 182 | background: url(../images/prevnext_bg.png) 0 0 repeat; 183 | width: 70px; 184 | top: 0 !important; 185 | bottom: 0; 186 | height: auto !important; 187 | 188 | right: -80px; 189 | display: block; 190 | position: absolute; 191 | opacity: 1 !important; 192 | transition: 0.5s ease; 193 | -o-transition: 0.5s ease; 194 | -webkit-transition: 0.5s ease; 195 | } 196 | 197 | .camera_thumbs_cont { 198 | z-index: 900; 199 | position: absolute; 200 | bottom: 0; 201 | left: 0; 202 | right: 0; 203 | } 204 | 205 | 206 | .camera_thumbs_cont > div { 207 | float: left; 208 | width: 100%; 209 | 210 | } 211 | .camera_thumbs_cont ul { 212 | background: url(../images/thumb_bg.png) 0 0 repeat; 213 | overflow: hidden; 214 | position: relative; 215 | width: 100% !important; 216 | margin: 0 !important; 217 | margin-left: 0px !important; 218 | left: 0% !important; 219 | margin-top: 0px !important; 220 | text-align: center; 221 | padding: 10px 0 10px; 222 | } 223 | .camera_thumbs_cont ul li { 224 | background-color: transparent; 225 | display: inline-block; 226 | font-size: 0; 227 | line-height: 0; 228 | transition: 0.5s ease; 229 | -o-transition: 0.5s ease; 230 | -webkit-transition: 0.5s ease; 231 | } 232 | 233 | .camera_thumbs_cont ul li+li { 234 | margin-left: 11px !important; 235 | } 236 | .camera_thumbs_cont ul li > img { 237 | cursor: pointer; 238 | opacity: 1 !important; 239 | vertical-align:bottom; 240 | transition: 0.5s ease; 241 | -o-transition: 0.5s ease; 242 | -webkit-transition: 0.5s ease; 243 | } 244 | 245 | 246 | 247 | 248 | 249 | .camera_thumbs_cont ul li:hover, .camera_thumbs_cont ul li.cameracurrent { 250 | opacity: 0.5; 251 | } 252 | .camera_clear { 253 | display: block; 254 | clear: both; 255 | } 256 | .showIt { 257 | display: none; 258 | } 259 | .camera_clear { 260 | clear: both; 261 | display: block; 262 | height: 1px; 263 | margin: -1px 0 25px; 264 | position: relative; 265 | text-align: right; 266 | } 267 | 268 | 269 | 270 | .caption { 271 | 272 | position: absolute; 273 | text-align: center; 274 | font-size: 24px; 275 | line-height: 60px; 276 | left: 0; 277 | right: 0; 278 | top: 41%; 279 | color: #fff; 280 | -moz-box-sizing: border-box; 281 | -webkit-box-sizing: border-box; 282 | -o-box-sizing: border-box; 283 | box-sizing: border-box; 284 | } 285 | 286 | .caption .price span { 287 | display: block; 288 | font-size: 48px; 289 | line-height: 48px; 290 | margin-top: -4px; 291 | } 292 | 293 | .caption a { 294 | margin-top: 30px; 295 | font: 18px/20px 'Open Sans', sans-serif; 296 | color: #fff; 297 | border-radius: 20px; 298 | text-transform: uppercase; 299 | padding: 12px 46px 13px; 300 | box-shadow: 3px 3px 5px 3px #193c46; 301 | 302 | display: inline-block; 303 | background-color: #7ecefd; 304 | background: url(../images/capt_a.png) 0 0 repeat-x #c5302c; 305 | 306 | } 307 | 308 | .caption a:hover { 309 | color: #fff; 310 | background-color: #002141; 311 | background-position: 0 -100px; 312 | } 313 | 314 | /************************** 315 | * 316 | * COLORS & SKINS 317 | * 318 | **************************/ 319 | 320 | 321 | /* 322 | .camera_pag { 323 | display: block; 324 | position: absolute; 325 | left: 50%; 326 | margin-left: -40px; 327 | bottom: -34px; 328 | overflow: hidden; 329 | float: left; 330 | z-index: 999; 331 | text-align: left; 332 | 333 | } 334 | 335 | .camera_pag_ul { 336 | overflow: hidden; 337 | 338 | 339 | } 340 | 341 | .camera_pag ul li { 342 | float: left; 343 | } 344 | 345 | .camera_pag ul li+li { 346 | margin-left: 11px; 347 | } 348 | 349 | .camera_pag ul li span { 350 | background: url(../images/pagination.png) right 0 no-repeat; 351 | display: block; 352 | width: 20px; 353 | height: 20px; 354 | overflow: hidden; 355 | color: transparent; 356 | text-indent: -100px; 357 | 358 | } 359 | 360 | .camera_pag ul li:hover span, .camera_pag ul li.cameracurrent span { 361 | cursor: pointer; 362 | background-position: 0 0; 363 | }*/ 364 | 365 | 366 | .camera_prev, .camera_next { 367 | display: block; 368 | position: absolute; 369 | width: 69px; 370 | height: 61px; 371 | left: 0; 372 | color: #cdcdce; 373 | cursor: pointer; 374 | top: 50%; 375 | margin-top: -35px; 376 | z-index: 999; 377 | background: url(../images/prevnext.png) 0 0 no-repeat; 378 | opacity: 1 !important; 379 | transition: width 0.5s ease; 380 | -o-transition: width 0.5s ease; 381 | -webkit-transition: width 0.5s ease; 382 | 383 | } 384 | 385 | 386 | 387 | .camera_next { 388 | right: 0; 389 | left: auto; 390 | background-position: right bottom; 391 | } 392 | 393 | .camera_prev:hover { 394 | width: 75px; 395 | background-position: 0 bottom; 396 | } 397 | 398 | .camera_next:hover { 399 | width: 75px; 400 | background-position: right 0; 401 | } 402 | 403 | 404 | -------------------------------------------------------------------------------- /static/css/chat.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro&display=swap"); 2 | * { 3 | box-sizing: border-box; 4 | } 5 | body { 6 | margin: 0; 7 | padding: 0; 8 | min-height: 100vh; 9 | font-family: "Source Sans Pro", sans-serif; 10 | background-color: #ecf0f1; 11 | background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23bdc3c7' fill-opacity='0.35'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 12 | } 13 | .container { 14 | width: 100%; 15 | height: 100%; 16 | } 17 | .container .status { 18 | position: fixed; 19 | top: 0; 20 | width: 70%; 21 | margin-left: 50%; 22 | transform: translateX(-50%); 23 | background-color: #2ecc71; 24 | color: #fff; 25 | padding: 8px; 26 | border-radius: 3px; 27 | font-weight: 600; 28 | } 29 | .container .messages { 30 | background-color: #ecf0f1; 31 | background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23bdc3c7' fill-opacity='0.35'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 32 | max-width: 70%; 33 | margin: 1rem auto; 34 | display: flex; 35 | flex-direction: column; 36 | } 37 | .container .messages > div { 38 | padding: 8px 12px; 39 | border: 1px solid #c4c4c4; 40 | width: auto; 41 | margin: 8px; 42 | background-color: #fff; 43 | } 44 | .container .messages > div .username { 45 | font-size: 12px; 46 | color: #3498db; 47 | margin-bottom: 4px; 48 | font-weight: 600; 49 | } 50 | .container .messages > div:last-child { 51 | margin-bottom: 3rem; 52 | } 53 | .container .messages .received { 54 | align-self: flex-start; 55 | border-radius: 5px 8px 6px 0; 56 | } 57 | .container .messages .sent { 58 | align-self: flex-end; 59 | border-radius: 5px 0 6px 8px; 60 | } 61 | .container form { 62 | position: fixed; 63 | bottom: 2px; 64 | width: 70%; 65 | display: flex; 66 | margin-left: 50%; 67 | transform: translateX(-50%); 68 | } 69 | .container form input { 70 | width: calc(100% - 100px); 71 | outline: none; 72 | padding: 12px; 73 | border: 1px solid #747474; 74 | border-radius: 4px; 75 | margin-right: 2px; 76 | font-size: 16px; 77 | } 78 | .container form button { 79 | width: 100px; 80 | padding: 12px 18px; 81 | border: none; 82 | background-color: #2ecc71; 83 | color: #fff; 84 | font-size: 22px; 85 | outline: none; 86 | border-radius: 0 5px 5px 0; 87 | cursor: pointer; 88 | transition: 0.2s all; 89 | } 90 | .container form button:active { 91 | transform: scale(0.97); 92 | } 93 | .toast { 94 | display: none; 95 | position: absolute; 96 | padding: 12px 30px; 97 | background-color: #57606f; 98 | color: #fff; 99 | border-radius: 3px; 100 | font-size: 14px; 101 | cursor: pointer; 102 | z-index: 99; 103 | top: 22px; 104 | right: 12px; 105 | } 106 | .show-top { 107 | display: block; 108 | animation: animate-top 0.1s forwards; 109 | } 110 | @keyframes animate-top { 111 | to { 112 | transform: translateY(8px); 113 | } 114 | } 115 | @media screen and (max-width: 700px) { 116 | .container { 117 | width: 100%; 118 | } 119 | .container .messages { 120 | max-width: 100%; 121 | } 122 | .container form { 123 | width: 100%; 124 | margin-left: 0; 125 | transform: translateX(0); 126 | } 127 | .container .status { 128 | width: 100%; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /static/css/detail-group.css: -------------------------------------------------------------------------------- 1 | @import "compass"; 2 | 3 | .mod-directions { 4 | font-family: "Arial"; 5 | display: flex; 6 | flex-direction: column; 7 | justify-content: center; 8 | align-items: center; 9 | margin-top: 50px; 10 | } 11 | .mod-directions .mod-directions-form .mod-directions-form-row { 12 | overflow: hidden; 13 | margin-bottom: 24px; 14 | } 15 | .mod-directions .mod-directions-form .mod-directions-form-row .mod-directions-form-label { 16 | display: inline-block; 17 | vertical-align: middle; 18 | width: 150px; 19 | font-weight: bold; 20 | font-size: 13px; 21 | } 22 | .mod-directions .mod-directions-form .mod-directions-form-row .mod-directions-form-input-block { 23 | display: inline-block; 24 | vertical-align: middle; 25 | padding: 6px; 26 | background: white; 27 | border: 2px solid lightgray; 28 | font-size: 14px; 29 | color: #34495e; 30 | outline: 0; 31 | } 32 | .mod-directions .mod-directions-form .mod-directions-form-row .mod-directions-form-input-block:focus, .mod-directions .mod-directions-form .mod-directions-form-row .mod-directions-form-input-block:active { 33 | border-color: #1abc9c; 34 | } 35 | .mod-directions .mod-directions-form .mod-directions-form-row .mod-directions-form-submit { 36 | margin-left: 150px; 37 | background: #1abc9c; 38 | color: white; 39 | padding: 8px 15px; 40 | border: none; 41 | } 42 | 43 | 44 | #mod-directions-form-submit{ 45 | width: 100%; 46 | } -------------------------------------------------------------------------------- /static/css/form.css: -------------------------------------------------------------------------------- 1 | /****Form****/ 2 | 3 | #form { 4 | padding-top: 15px; 5 | } 6 | 7 | #form input { 8 | width: 100%; 9 | height: 31px; 10 | float:left; 11 | background: #fefefe; 12 | box-sizing: border-box; 13 | -webkit-appearance: none; 14 | -moz-box-sizing: border-box; /*Firefox 1-3*/ 15 | -webkit-box-sizing: border-box; /* Safari */ 16 | color: #878787; 17 | font: 14px/20px 'Open Sans', sans-serif; 18 | border: 1px solid #f0efef; 19 | padding: 5px 18px 7px; 20 | } 21 | 22 | 23 | #form textarea { 24 | width: 100%; 25 | height: 221px; 26 | background: #fefefe; 27 | position: relative; 28 | resize:none; 29 | overflow: hidden; 30 | box-sizing: border-box; 31 | -webkit-appearance: none; 32 | -moz-box-sizing: border-box; /*Firefox 1-3*/ 33 | -webkit-box-sizing: border-box; /* Safari */ 34 | float:left; 35 | margin: 0; 36 | color: #878787; 37 | font: 14px/20px 'Open Sans', sans-serif; 38 | border: 1px solid #f0efef; 39 | padding: 11px 18px 7px; 40 | } 41 | 42 | #form .message ._placeholder { 43 | padding-top: 22px; 44 | } 45 | 46 | 47 | 48 | #form ._placeholder { 49 | transition: 0.5s ease; 50 | -o-transition: 0.5s ease; 51 | -webkit-transition: 0.5s ease; 52 | color: #878787; 53 | font: 14px/20px 'Open Sans', sans-serif; 54 | border: 1px solid transparent; 55 | padding: 5px 28px 5px; 56 | height: 30px !important; 57 | width: 100% !important; 58 | box-sizing: border-box; 59 | -moz-box-sizing: border-box; /*Firefox 1-3*/ 60 | -webkit-box-sizing: border-box; /* Safari */ 61 | position: absolute; 62 | right: 0; 63 | top: 0; 64 | bottom: 0; 65 | left: 0; 66 | cursor: text !important; 67 | display: block; 68 | } 69 | 70 | #form ._placeholder.hidden { 71 | display: none; 72 | } 73 | 74 | #form ._placeholder.focused { 75 | opacity: 0.3; 76 | } 77 | 78 | 79 | #form .message ._placeholder { 80 | height: 100% !important; 81 | } 82 | #form label { 83 | position:relative; 84 | display: block; 85 | min-height: 40px; 86 | float: left; 87 | width: 170px; 88 | } 89 | 90 | 91 | #form label+label { 92 | margin-left: 30px; 93 | } 94 | 95 | 96 | #form label.message { 97 | width: 100%; 98 | position: relative; 99 | margin-left: 0; 100 | } 101 | 102 | 103 | 104 | 105 | #form .error-message, #form .empty-message { 106 | color: #E02A05; 107 | font-size: 11px; 108 | line-height:14px; 109 | width:auto; 110 | position: absolute; 111 | z-index: 999; 112 | bottom: -3px; 113 | opacity: 0; 114 | right: 5px; 115 | float:left; 116 | transition: 0.5s ease; 117 | -o-transition: 0.5s ease; 118 | -webkit-transition: 0.5s ease; 119 | } 120 | 121 | #form .message .error-message, #form .message .empty-message { 122 | bottom: -16px; 123 | } 124 | 125 | 126 | 127 | 128 | #form .invalid .error-message, #form .empty .empty-message { 129 | opacity: 1; 130 | } 131 | 132 | .btns { 133 | font-size: 0; 134 | line-height: 0; 135 | text-align: right; 136 | padding-top: 28px; 137 | } 138 | 139 | .btns a.btn { 140 | margin: 0; 141 | padding-left: 0; 142 | padding-right: 0; 143 | min-width: 85px; 144 | display: inline-block; 145 | text-align: center; 146 | 147 | } 148 | 149 | .btns a.btn+a.btn { 150 | margin-left: 8px; 151 | } 152 | 153 | 154 | 155 | 156 | 157 | 158 | .phone { 159 | position: relative; 160 | } 161 | 162 | 163 | 164 | .message br { 165 | height: 0; 166 | line-height: 0; 167 | } 168 | 169 | #form .success-message { 170 | display: none; 171 | opacity: 0; 172 | position: absolute; 173 | background: #fefefe; 174 | border: 1px solid #f0efef; 175 | width: 100%; 176 | height: 40px; 177 | text-align: center; 178 | padding: 9px 10px; 179 | z-index: 999; 180 | box-sizing: border-box; 181 | -moz-box-sizing: border-box; /*Firefox 1-3*/ 182 | -webkit-box-sizing: border-box; /* Safari */ 183 | transition: 0.5s ease; 184 | -o-transition: 0.5s ease; 185 | -webkit-transition: 0.5s ease; 186 | } 187 | 188 | #form.success .success-message { 189 | display: block; 190 | opacity: 1; 191 | } 192 | 193 | .success_wrapper { 194 | position: relative; 195 | } 196 | 197 | @media only screen and (max-width: 995px) { 198 | 199 | #form { 200 | } 201 | 202 | 203 | #form label { 204 | float: none !important; 205 | width: 100%; 206 | margin-left: 0 !important; 207 | } 208 | 209 | #form input { 210 | margin-bottom: 10px; 211 | } 212 | 213 | 214 | #form .success-message { 215 | width: 100%; 216 | } 217 | 218 | .btns { 219 | padding-right: 0; 220 | } 221 | 222 | #form label.email { 223 | width: 100%; 224 | margin: 0; 225 | } 226 | 227 | .map figure { 228 | float: left !important; 229 | margin-right: 0px !important; 230 | } 231 | 232 | 233 | } 234 | 235 | @media only screen and (max-width: 767px) { 236 | 237 | 238 | .map figure { 239 | width: 100% !important; 240 | float: none !important; 241 | display: block !important; 242 | margin-right: 0px !important; 243 | } 244 | .btns { 245 | padding-bottom: 0; 246 | } 247 | 248 | #form textarea { 249 | height: 300px !important; 250 | } 251 | 252 | #form { 253 | padding-right: 0; 254 | } 255 | 256 | } 257 | @media only screen and (max-width: 479px) { 258 | 259 | #form textarea { 260 | height: 200px !important; 261 | } 262 | } -------------------------------------------------------------------------------- /static/css/grid.css: -------------------------------------------------------------------------------- 1 | /* 2 | Variable Grid System. 3 | Learn more ~ http://www.spry-soft.com/grids/ 4 | Based on 960 Grid System - http://960.gs/ 5 | 6 | Licensed under GPL and MIT. 7 | */ 8 | 9 | /* 10 | Forces backgrounds to span full width, 11 | even if there is horizontal scrolling. 12 | Increase this if your layout is wider. 13 | 14 | Note: IE6 works fine without this fix. 15 | */ 16 | 17 | body { 18 | min-width: 1200px; 19 | } 20 | 21 | /* Containers 22 | ----------------------------------------------------------------------------------------------------*/ 23 | .container_12 { 24 | margin-left: auto; 25 | margin-right: auto; 26 | width: 1200px; 27 | } 28 | 29 | /* Grid >> Global 30 | ----------------------------------------------------------------------------------------------------*/ 31 | 32 | 33 | .grid_1, 34 | .grid_2, 35 | .grid_3, 36 | .grid_4, 37 | .grid_5, 38 | .grid_6, 39 | .grid_7, 40 | .grid_8, 41 | .grid_9, 42 | .grid_10, 43 | .grid_11, 44 | .grid_12 { 45 | display:inline; 46 | float: left; 47 | position: relative; 48 | margin-left: 15px; 49 | margin-right: 15px; 50 | } 51 | 52 | 53 | 54 | .push_1, .pull_1, 55 | .push_2, .pull_2, 56 | .push_3, .pull_3, 57 | .push_4, .pull_4, 58 | .push_5, .pull_5, 59 | .push_6, .pull_6, 60 | .push_7, .pull_7, 61 | .push_8, .pull_8, 62 | .push_9, .pull_9, 63 | .push_10, .pull_10, 64 | .push_11, .pull_11, 65 | .push_12, .pull_12 { 66 | position:relative; 67 | } 68 | 69 | 70 | /* Grid >> Children (Alpha ~ First, Omega ~ Last) 71 | ----------------------------------------------------------------------------------------------------*/ 72 | 73 | .alpha { 74 | margin-left: 0; 75 | } 76 | 77 | .omega { 78 | margin-right: 0; 79 | } 80 | 81 | /* Grid >> 12 Columns 82 | ----------------------------------------------------------------------------------------------------*/ 83 | 84 | 85 | .container_12 .grid_1 { 86 | width:70px; 87 | } 88 | 89 | .container_12 .grid_2 { 90 | width:170px; 91 | } 92 | 93 | .container_12 .grid_3 { 94 | width:270px; 95 | } 96 | 97 | .container_12 .grid_4 { 98 | width:370px; 99 | } 100 | 101 | .container_12 .grid_5 { 102 | width:470px; 103 | } 104 | 105 | .container_12 .grid_6 { 106 | width:570px; 107 | } 108 | 109 | .container_12 .grid_7 { 110 | width:670px; 111 | } 112 | 113 | .container_12 .grid_8 { 114 | width:770px; 115 | } 116 | 117 | .container_12 .grid_9 { 118 | width:870px; 119 | } 120 | 121 | .container_12 .grid_10 { 122 | width:970px; 123 | } 124 | 125 | .container_12 .grid_11 { 126 | width:1070px; 127 | } 128 | 129 | .container_12 .grid_12 { 130 | width:1170px; 131 | } 132 | 133 | 134 | 135 | 136 | /* Prefix Extra Space >> 12 Columns 137 | ----------------------------------------------------------------------------------------------------*/ 138 | 139 | 140 | .container_12 .prefix_1 { 141 | padding-left:100px; 142 | } 143 | 144 | .container_12 .prefix_2 { 145 | padding-left:200px; 146 | } 147 | 148 | .container_12 .prefix_3 { 149 | padding-left:300px; 150 | } 151 | 152 | .container_12 .prefix_4 { 153 | padding-left:400px; 154 | } 155 | 156 | .container_12 .prefix_5 { 157 | padding-left:500px; 158 | } 159 | 160 | .container_12 .prefix_6 { 161 | padding-left:600px; 162 | } 163 | 164 | .container_12 .prefix_7 { 165 | padding-left:700px; 166 | } 167 | 168 | .container_12 .prefix_8 { 169 | padding-left:800px; 170 | } 171 | 172 | .container_12 .prefix_9 { 173 | padding-left:900px; 174 | } 175 | 176 | .container_12 .prefix_10 { 177 | padding-left:1000px; 178 | } 179 | 180 | .container_12 .prefix_11 { 181 | padding-left:1100px; 182 | } 183 | 184 | 185 | 186 | /* Suffix Extra Space >> 12 Columns 187 | ----------------------------------------------------------------------------------------------------*/ 188 | 189 | 190 | .container_12 .suffix_1 { 191 | padding-right:100px; 192 | } 193 | 194 | .container_12 .suffix_2 { 195 | padding-right:200px; 196 | } 197 | 198 | .container_12 .suffix_3 { 199 | padding-right:300px; 200 | } 201 | 202 | .container_12 .suffix_4 { 203 | padding-right:400px; 204 | } 205 | 206 | .container_12 .suffix_5 { 207 | padding-right:500px; 208 | } 209 | 210 | .container_12 .suffix_6 { 211 | padding-right:600px; 212 | } 213 | 214 | .container_12 .suffix_7 { 215 | padding-right:700px; 216 | } 217 | 218 | .container_12 .suffix_8 { 219 | padding-right:800px; 220 | } 221 | 222 | .container_12 .suffix_9 { 223 | padding-right:900px; 224 | } 225 | 226 | .container_12 .suffix_10 { 227 | padding-right:1000px; 228 | } 229 | 230 | .container_12 .suffix_11 { 231 | padding-right:1100px; 232 | } 233 | 234 | 235 | 236 | /* Push Space >> 12 Columns 237 | ----------------------------------------------------------------------------------------------------*/ 238 | 239 | 240 | .container_12 .push_1 { 241 | left:100px; 242 | } 243 | 244 | .container_12 .push_2 { 245 | left:200px; 246 | } 247 | 248 | .container_12 .push_3 { 249 | left:300px; 250 | } 251 | 252 | .container_12 .push_4 { 253 | left:400px; 254 | } 255 | 256 | .container_12 .push_5 { 257 | left:500px; 258 | } 259 | 260 | .container_12 .push_6 { 261 | left:600px; 262 | } 263 | 264 | .container_12 .push_7 { 265 | left:700px; 266 | } 267 | 268 | .container_12 .push_8 { 269 | left:800px; 270 | } 271 | 272 | .container_12 .push_9 { 273 | left:900px; 274 | } 275 | 276 | .container_12 .push_10 { 277 | left:1000px; 278 | } 279 | 280 | .container_12 .push_11 { 281 | left:1100px; 282 | } 283 | 284 | 285 | 286 | /* Pull Space >> 12 Columns 287 | ----------------------------------------------------------------------------------------------------*/ 288 | 289 | 290 | .container_12 .pull_1 { 291 | left:-100px; 292 | } 293 | 294 | .container_12 .pull_2 { 295 | left:-200px; 296 | } 297 | 298 | .container_12 .pull_3 { 299 | left:-300px; 300 | } 301 | 302 | .container_12 .pull_4 { 303 | left:-400px; 304 | } 305 | 306 | .container_12 .pull_5 { 307 | left:-500px; 308 | } 309 | 310 | .container_12 .pull_6 { 311 | left:-600px; 312 | } 313 | 314 | .container_12 .pull_7 { 315 | left:-700px; 316 | } 317 | 318 | .container_12 .pull_8 { 319 | left:-800px; 320 | } 321 | 322 | .container_12 .pull_9 { 323 | left:-900px; 324 | } 325 | 326 | .container_12 .pull_10 { 327 | left:-1000px; 328 | } 329 | 330 | .container_12 .pull_11 { 331 | left:-1100px; 332 | } 333 | 334 | 335 | 336 | 337 | /* `Clear Floated Elements 338 | ----------------------------------------------------------------------------------------------------*/ 339 | 340 | 341 | 342 | /* http://www.yuiblog.com/blog/2010/09/27/clearfix-reloaded-overflowhidden-demystified */ 343 | 344 | .clearfix:before, 345 | .clearfix:after { 346 | content: '\0020'; 347 | display: block; 348 | overflow: hidden; 349 | visibility: hidden; 350 | width: 0; 351 | height: 0; 352 | } 353 | 354 | .clearfix:after { 355 | clear: both; 356 | } 357 | 358 | /* 359 | The following zoom:1 rule is specifically for IE6 + IE7. 360 | Move to separate stylesheet if invalid CSS is a problem. 361 | */ 362 | 363 | .clearfix { 364 | zoom: 1; 365 | } -------------------------------------------------------------------------------- /static/css/ie.css: -------------------------------------------------------------------------------- 1 | 2 | .socials a { 3 | behavior: url(js/PIE.htc); 4 | position: relative; 5 | } 6 | 7 | 8 | .clear.height1 { 9 | height: 33px !important; 10 | } 11 | 12 | .socials a { 13 | margin-right: 9px; 14 | } 15 | 16 | 17 | #form .invalid .error-message, #form .empty .empty-message { 18 | display: block; 19 | } 20 | 21 | #form .error-message, #form .empty-message { 22 | display: none; 23 | } 24 | 25 | a.gal:hover img { 26 | filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20); 27 | 28 | } -------------------------------------------------------------------------------- /static/css/owl.carousel.css: -------------------------------------------------------------------------------- 1 | #owl { 2 | overflow: hidden; 3 | z-index: 1; 4 | position: relative; 5 | padding-top: 80px; 6 | margin: -41px -10px 0; 7 | } 8 | 9 | 10 | 11 | #owl .owl-item { 12 | float: left; 13 | width: 100%; 14 | } 15 | 16 | #owl .item { 17 | padding: 0 10px; 18 | position: relative; 19 | text-align: left; 20 | } 21 | 22 | #owl .item .clear { 23 | height: 10px; 24 | } 25 | 26 | #owl .item .text1 { 27 | margin-bottom: 4px; 28 | } 29 | 30 | .owl-wrapper-outer { 31 | overflow: hidden; 32 | } 33 | 34 | 35 | #owl .owl-prev, #owl .owl-next { 36 | cursor: pointer; 37 | position: absolute; 38 | background: url(../images/prevnext.png) 0 0 no-repeat; 39 | display: block; 40 | height: 25px; 41 | right: 38px; 42 | top: 0; 43 | width: 17px; 44 | overflow: hidden; 45 | text-indent: -999px; 46 | 47 | } 48 | 49 | #owl .owl-next { 50 | right: 10px; 51 | background-position: right bottom; 52 | 53 | } 54 | #owl .owl-next:hover { 55 | background-position: right 0; 56 | } 57 | 58 | 59 | 60 | #owl .owl-prev:hover { 61 | background-position: 0 bottom; 62 | } 63 | 64 | 65 | 66 | 67 | 68 | /* Owl content */ 69 | 70 | 71 | 72 | .owl-carousel .owl-wrapper{ 73 | display: none; 74 | position: relative; 75 | -webkit-transform: translate3d(0px, 0px, 0px); 76 | -webkit-perspective: 1000; 77 | } 78 | 79 | 80 | /*2nd*/ 81 | #owl1 { 82 | overflow: hidden; 83 | z-index: 1; 84 | position: relative; 85 | padding-top: 97px; 86 | margin: -53px -10px 0; 87 | } 88 | 89 | 90 | #owl1 .owl-item { 91 | float: left; 92 | width: 100%; 93 | } 94 | 95 | #owl1 .item { 96 | padding: 0 10px; 97 | position: relative; 98 | text-align: left; 99 | } 100 | 101 | #owl1 .item .count { 102 | background: url(../images/count_icon.png) 0 0 no-repeat; 103 | width: 60px; 104 | height: 66px; 105 | float: left; 106 | margin-right: 20px; 107 | text-align: center; 108 | color: #3498db; 109 | font: 30px/82px 'Bitter', serif; 110 | } 111 | 112 | #owl1 .item .text1 { 113 | padding-top: 11px; 114 | color: #3498db; 115 | } 116 | 117 | #owl1 .item .text1 .col2 { 118 | display: block; 119 | line-height: 15px; 120 | font-size: 15px; 121 | padding-top: 3px; 122 | } 123 | 124 | #owl1 .item .clear { 125 | height: 21px; 126 | } 127 | 128 | .owl-wrapper-outer { 129 | overflow: hidden; 130 | } 131 | 132 | #owl1 .owl-prev, #owl1 .owl-next { 133 | cursor: pointer; 134 | position: absolute; 135 | background: url(../images/prevnext.png) 0 0 no-repeat; 136 | display: block; 137 | height: 25px; 138 | right: 38px; 139 | top: 0; 140 | width: 17px; 141 | overflow: hidden; 142 | text-indent: -999px; 143 | 144 | } 145 | 146 | #owl1 .owl-next { 147 | right: 10px; 148 | background-position: right bottom; 149 | 150 | } 151 | #owl1 .owl-next:hover { 152 | background-position: right 0; 153 | } 154 | 155 | 156 | 157 | #owl1 .owl-prev:hover { 158 | background-position: 0 bottom; 159 | } 160 | -------------------------------------------------------------------------------- /static/css/reset.css: -------------------------------------------------------------------------------- 1 | a,abbr,acronym,address,applet,article,aside,audio,b,blockquote,big,body,center,canvas,caption,cite,code,command,datalist,dd,del,details,dfn,dl,div,dt,em,embed,fieldset,figcaption,figure,font,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,keygen,label,legend,li,meter,nav,object,ol,output,p,pre,progress,q,s,samp,section,small,span,source,strike,strong,sub,sup,table,tbody,tfoot,thead,th,tr,tdvideo,tt,u,ul,var{background:transparent;border:0 none;font-size:100%;margin:0;padding:0;border:0;outline:0;vertical-align:top;}ol, ul {list-style:none;}blockquote, q {quotes:none;}table, table td {padding:0;border:none;border-collapse:collapse;}img {vertical-align:top;}embed {vertical-align:top;}input[type=text], textarea{ outline:none;border-radius:0;} -------------------------------------------------------------------------------- /static/css/skeleton.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V1.1 3 | * Copyright 2011, Dave Gamache 4 | * www.getskeleton.com 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8/17/2011 8 | */ 9 | 10 | 11 | /* Table of Contents 12 | ================================================== 13 | #Base 960 Grid 14 | #Tablet (Portrait) 15 | #Mobile (Portrait) 16 | #Mobile (Landscape) 17 | #Clearing */ 18 | 19 | 20 | 21 | /* #Base 960 Grid 22 | ================================================== */ 23 | 24 | .container_12{ position: relative; width: 960px; margin: 0 auto; padding: 0; } 25 | .grid_1, 26 | .grid_2, 27 | .grid_3, 28 | .grid_4, 29 | .grid_5, 30 | .grid_6, 31 | .grid_7, 32 | .grid_8, 33 | .grid_9, 34 | .grid_10, 35 | .grid_11, 36 | .grid_12 37 | { float: left; display: inline; margin-left: 10px; margin-right: 10px; } 38 | 39 | /* Nested Column Classes */ 40 | .container_12 .alpha { margin-left: 0; } 41 | .container_12 .omega { margin-right: 0; } 42 | 43 | /* Base Grid */ 44 | .container_12 .grid_1 { width: 60px; } 45 | .container_12 .grid_2 { width: 140px; } 46 | .container_12 .grid_3 { width: 220px; } 47 | .container_12 .grid_4 { width: 300px; } 48 | .container_12 .grid_5 { width: 380px; } 49 | .container_12 .grid_6 { width: 460px; } 50 | .container_12 .grid_7 { width: 540px; } 51 | .container_12 .grid_8 { width: 620px; } 52 | .container_12 .grid_9 { width: 700px; } 53 | .container_12 .grid_10 { width: 780px; } 54 | .container_12 .grid_11 { width: 860px; } 55 | .container_12 .grid_12 { width: 940px; } 56 | /* Prefix Extra Space >> 12 Columns */ 57 | .container_12 .prefix_1 {padding-left:80px;} 58 | .container_12 .prefix_2 {padding-left:160px;} 59 | .container_12 .prefix_3 {padding-left:240px;} 60 | .container_12 .prefix_4 {padding-left:320px;} 61 | .container_12 .prefix_5 {padding-left:400px;} 62 | .container_12 .prefix_6 {padding-left:480px;} 63 | .container_12 .prefix_7 {padding-left:560px;} 64 | .container_12 .prefix_8 {padding-left:640px;} 65 | .container_12 .prefix_9 {padding-left:720px;} 66 | .container_12 .prefix_10 {padding-left:800px;} 67 | .container_12 .prefix_11 {padding-left:880px;} 68 | /* Suffix Extra Space >> 12 Columns */ 69 | .container_12 .suffix_1 {padding-right:80px;} 70 | .container_12 .suffix_2 {padding-right:160px;} 71 | .container_12 .suffix_3 {padding-right:240px;} 72 | .container_12 .suffix_4 {padding-right:320px;} 73 | .container_12 .suffix_5 {padding-right:400px;} 74 | .container_12 .suffix_6 {padding-right:480px;} 75 | .container_12 .suffix_7 {padding-right:560px;} 76 | .container_12 .suffix_8 {padding-right:640px;} 77 | .container_12 .suffix_9 {padding-right:720px;} 78 | .container_12 .suffix_10 {padding-right:800px;} 79 | .container_12 .suffix_11 {padding-right:880px;} 80 | 81 | /* #Tablet (Portrait) 82 | ================================================== */ 83 | 84 | /* Note: Design for a width of 768px */ 85 | 86 | @media only screen and (min-width: 768px) and (max-width: 995px) { 87 | .container_12 { width: 768px; } 88 | .grid_1, 89 | .grid_2, 90 | .grid_3, 91 | .grid_4, 92 | .grid_5, 93 | .grid_6, 94 | .grid_7, 95 | .grid_8, 96 | .grid_9, 97 | .grid_10, 98 | .grid_11, 99 | .grid_12 100 | { margin-left: 10px; margin-right: 10px; } 101 | .container_12 .alpha { margin-left: 0;} 102 | .container_12 .omega { margin-right: 0;} 103 | 104 | .container_12 .grid_1 { width: 44px; } 105 | .container_12 .grid_2 { width: 108px; } 106 | .container_12 .grid_3 { width: 172px; } 107 | .container_12 .grid_4 { width: 236px; } 108 | .container_12 .grid_5 { width: 300px; } 109 | .container_12 .grid_6 { width: 364px; } 110 | .container_12 .grid_7 { width: 428px; } 111 | .container_12 .grid_8 { width: 492px; } 112 | .container_12 .grid_9 { width: 556px; } 113 | .container_12 .grid_10 { width: 620px; } 114 | .container_12 .grid_11 { width: 684px; } 115 | .container_12 .grid_12 { width: 748px; } 116 | /* Prefix Extra Space >> 12 Columns */ 117 | .container_12 .prefix_1 {padding-left:64px;} 118 | .container_12 .prefix_2 {padding-left:128px;} 119 | .container_12 .prefix_3 {padding-left:192px;} 120 | .container_12 .prefix_4 {padding-left:256px;} 121 | .container_12 .prefix_5 {padding-left:320px;} 122 | .container_12 .prefix_6 {padding-left:384px;} 123 | .container_12 .prefix_7 {padding-left:448px;} 124 | .container_12 .prefix_8 {padding-left:512px;} 125 | .container_12 .prefix_9 {padding-left:576px;} 126 | .container_12 .prefix_10 {padding-left:640px;} 127 | .container_12 .prefix_11 {padding-left:768px;} 128 | /* Suffix Extra Space >> 12 Columns */ 129 | .container_12 .suffix_1 {padding-right:64px;} 130 | .container_12 .suffix_2 {padding-right:128px;} 131 | .container_12 .suffix_3 {padding-right:192px;} 132 | .container_12 .suffix_4 {padding-right:256px;} 133 | .container_12 .suffix_5 {padding-right:320px;} 134 | .container_12 .suffix_6 {padding-right:384px;} 135 | .container_12 .suffix_7 {padding-right:448px;} 136 | .container_12 .suffix_8 {padding-right:512px;} 137 | .container_12 .suffix_9 {padding-right:576px;} 138 | .container_12 .suffix_10 {padding-right:640px;} 139 | .container_12 .suffix_11 {padding-right:768px;} 140 | } 141 | 142 | 143 | /* #Mobile (Portrait) 144 | ================================================== */ 145 | 146 | /* Note: Design for a width of 320px */ 147 | 148 | @media only screen and (max-width: 767px) { 149 | .container_12{width: 300px;} 150 | .grid_1, 151 | .grid_2, 152 | .grid_3, 153 | .grid_4, 154 | .grid_5, 155 | .grid_6, 156 | .grid_7, 157 | .grid_8, 158 | .grid_9, 159 | .grid_10, 160 | .grid_11, 161 | .grid_12{margin: 0;} 162 | 163 | .container_12 .grid_1, 164 | .container_12 .grid_2, 165 | .container_12 .grid_3, 166 | .container_12 .grid_4, 167 | .container_12 .grid_5, 168 | .container_12 .grid_6, 169 | .container_12 .grid_7, 170 | .container_12 .grid_8, 171 | .container_12 .grid_9, 172 | .container_12 .grid_10, 173 | .container_12 .grid_11, 174 | .container_12 .grid_12{width: 300px;} 175 | /* Prefix Extra Space >> 12 Columns */ 176 | .container_12 .prefix_1, 177 | .container_12 .prefix_2, 178 | .container_12 .prefix_3, 179 | .container_12 .prefix_4, 180 | .container_12 .prefix_5, 181 | .container_12 .prefix_6, 182 | .container_12 .prefix_7, 183 | .container_12 .prefix_8, 184 | .container_12 .prefix_9, 185 | .container_12 .prefix_10, 186 | .container_12 .prefix_11{padding-left:0;} 187 | /* Suffix Extra Space >> 12 Columns */ 188 | .container_12 .suffix_1, 189 | .container_12 .suffix_2, 190 | .container_12 .suffix_3, 191 | .container_12 .suffix_4, 192 | .container_12 .suffix_5, 193 | .container_12 .suffix_6, 194 | .container_12 .suffix_7, 195 | .container_12 .suffix_8, 196 | .container_12 .suffix_9, 197 | .container_12 .suffix_10, 198 | .container_12 .suffix_11{padding-right:0;} 199 | } 200 | 201 | 202 | /* #Mobile (Landscape) 203 | ================================================== */ 204 | 205 | /* Note: Design for a width of 480px */ 206 | 207 | @media only screen and (min-width: 480px) and (max-width: 767px) { 208 | .container_12 { width: 420px; } 209 | .grid_1, 210 | .grid_2, 211 | .grid_3, 212 | .grid_4, 213 | .grid_5, 214 | .grid_6, 215 | .grid_7, 216 | .grid_8, 217 | .grid_9, 218 | .grid_10, 219 | .grid_11, 220 | .grid_12{margin: 0;} 221 | 222 | .container_12 .grid_1, 223 | .container_12 .grid_2, 224 | .container_12 .grid_3, 225 | .container_12 .grid_4, 226 | .container_12 .grid_5, 227 | .container_12 .grid_6, 228 | .container_12 .grid_7, 229 | .container_12 .grid_8, 230 | .container_12 .grid_9, 231 | .container_12 .grid_10, 232 | .container_12 .grid_11, 233 | .container_12 .grid_12{width: 420px;} 234 | /* Prefix Extra Space >> 12 Columns */ 235 | .container_12 .prefix_1, 236 | .container_12 .prefix_2, 237 | .container_12 .prefix_3, 238 | .container_12 .prefix_4, 239 | .container_12 .prefix_5, 240 | .container_12 .prefix_6, 241 | .container_12 .prefix_7, 242 | .container_12 .prefix_8, 243 | .container_12 .prefix_9, 244 | .container_12 .prefix_10, 245 | .container_12 .prefix_11{padding-left:0;} 246 | /* Suffix Extra Space >> 12 Columns */ 247 | .container_12 .suffix_1, 248 | .container_12 .suffix_2, 249 | .container_12 .suffix_3, 250 | .container_12 .suffix_4, 251 | .container_12 .suffix_5, 252 | .container_12 .suffix_6, 253 | .container_12 .suffix_7, 254 | .container_12 .suffix_8, 255 | .container_12 .suffix_9, 256 | .container_12 .suffix_10, 257 | .container_12 .suffix_11{padding-right:0;} 258 | } 259 | 260 | 261 | /* #Clearing 262 | ================================================== */ 263 | 264 | /* Self Clearing Goodness */ 265 | .container_12:after { content: "\0020"; display: block; height: 0; clear: both; visibility: hidden; } 266 | 267 | /* Use clearfix class on parent to clear nested columns, 268 | or wrap each row of columns in a
*/ 269 | .clearfix:before, 270 | .clearfix:after, 271 | .row:before, 272 | .row:after { 273 | content: '\0020'; 274 | display: block; 275 | overflow: hidden; 276 | visibility: hidden; 277 | width: 0; 278 | height: 0; } 279 | .row:after, 280 | .clearfix:after { 281 | clear: both; } 282 | .row, 283 | .clearfix { 284 | zoom: 1; } 285 | 286 | /* You can also use a
to clear columns */ 287 | .clear { 288 | clear: both; 289 | display: block; 290 | overflow: hidden; 291 | visibility: hidden; 292 | width: 0; 293 | height: 0; 294 | } 295 | 296 | 297 | -------------------------------------------------------------------------------- /static/css/superfish.css: -------------------------------------------------------------------------------- 1 | 2 | .menu_block { 3 | z-index: 999; 4 | position: relative; 5 | background: url(../images/menu_bg.png) 0 0 repeat-x #d8d8db; 6 | padding: 12px 0 11px; 7 | } 8 | 9 | 10 | .menu_block nav { 11 | position: relative; 12 | font-family: 'Marvel', sans-serif; 13 | } 14 | 15 | 16 | nav>.sf-menu { 17 | z-index: 990; 18 | text-align: center; 19 | position: relative; 20 | } 21 | nav{ position:relative;padding: 0px 0 0 0;} 22 | .sf-menu ul {position:absolute;top:-999px; display:none;/* left offset of submenus need to match (see below) */} 23 | .sf-menu>li { 24 | display: block; 25 | position: relative; 26 | display: inline-block; 27 | font-size: 24px; 28 | line-height: 20px; 29 | 30 | } 31 | 32 | .sf-menu>li>ul>li { 33 | float: none; 34 | position: static; 35 | } 36 | 37 | .sf-menu>li+li { 38 | margin-left: 27px; 39 | } 40 | 41 | .sf-menu>li>a{ 42 | font-weight: bold; 43 | text-align: center; 44 | color: #313030; 45 | display: block; 46 | padding: 9px 25px; 47 | 48 | } 49 | 50 | .sf-menu>li.sfHover>a, .sf-menu>li.current>a, .sf-menu>li>a:hover { 51 | color: #000; 52 | background-color: #fdc903;} 53 | 54 | 55 | .sf-menu>li>a.sf-with-ul:after { 56 | position: absolute; 57 | content: ''; 58 | left: 50%; 59 | margin-left: -3px; 60 | width: 5px; 61 | background: url(../images/arrows.png) 0 0 no-repeat; 62 | height: 4px; 63 | bottom: 10px; 64 | pointer-events: none; 65 | z-index: 999; 66 | display: block; 67 | } 68 | 69 | .sf-menu>li.current>a.sf-with-ul:after, 70 | .sf-menu>li.sfHover>a.sf-with-ul:after { 71 | } 72 | 73 | .sf-menu>li>ul>li>a.sf-with-ul:after { 74 | content: ''; 75 | font-family: 'FontAwesome'; 76 | position: absolute; 77 | width: 5px; 78 | font-size: 15px; 79 | line-height: 13px; 80 | font-weight: normal; 81 | right: -15px; 82 | color: #fff; 83 | bottom: 3px; 84 | pointer-events: none; 85 | z-index: 999; 86 | } 87 | 88 | 89 | 90 | 91 | /*================================>> 2 Level <<========================================*/ 92 | .sf-menu li ul,.sf-menu li.sfHover>ul{ 93 | left: 0; 94 | z-index: 999; 95 | width: 100%; 96 | padding-top: 38px; 97 | background-color: #3498db; 98 | top: 81px; 99 | padding-bottom: 42px; 100 | 101 | } 102 | 103 | .sf-menu>li>ul>li>ul:after { 104 | content: ''; 105 | display: block; 106 | position: absolute; 107 | top: 13px; 108 | left: -5px; 109 | width: 0px; 110 | height: 0px; 111 | border-style: solid; 112 | border-width: 5px 5px 5px 0; 113 | border-color: transparent #3d454b transparent transparent; 114 | } 115 | 116 | 117 | .sf-menu li ul li { 118 | position: relative; 119 | text-align: center; 120 | float: none !important; 121 | font-size: 14px; 122 | line-height: 15px; 123 | font-weight: 600; 124 | text-transform: uppercase; 125 | color: #fff; 126 | } 127 | 128 | .sf-menu li ul li+li { 129 | margin-top: 13px; 130 | } 131 | 132 | .sf-menu li ul li+li+li { 133 | margin-top: 12px; 134 | } 135 | 136 | .sf-menu li ul li+li a { 137 | } 138 | 139 | 140 | .sf-menu li ul li a{ 141 | text-transform: uppercase; 142 | position: relative; 143 | z-index: 999; 144 | color: #fff; 145 | } 146 | 147 | 148 | 149 | 150 | 151 | .sf-menu li li a:hover, 152 | .sf-menu li.sfHover li.sfHover>a { 153 | color: #3d454b; 154 | } 155 | 156 | /*================================>> 3 Level <<========================================*/ 157 | .sf-menu li.sfHover li.sfHover ul{ 158 | position: absolute; 159 | padding-top: 32px; 160 | padding-bottom: 35px; 161 | left: 203px; 162 | top: -9px; 163 | width: 135px; 164 | background-color: #3d454b; 165 | } 166 | 167 | .sf-menu li ul ul li a:hover 168 | { 169 | color: #3498db; 170 | } 171 | 172 | 173 | /*==================================RESPONSIVE LAYOUTS===============================================*/ 174 | 175 | 176 | @media only screen and (max-width: 995px) { 177 | 178 | 179 | .sf-menu>li{ 180 | } 181 | 182 | .sf-menu li.sfHover li.sfHover ul{ 183 | left: 155px; 184 | } 185 | } 186 | 187 | @media only screen and (max-width: 767px) { 188 | .menu_block { 189 | float: none !important; 190 | padding: 20px 10px 25px !important; 191 | clear: both; 192 | min-height: 0px; 193 | border: none; 194 | } 195 | 196 | 197 | 198 | .menu_block nav{ 199 | border: none !important; 200 | float:none !important; 201 | font:12px/15px Arial, Helvetica, sans-serif; 202 | text-transform:uppercase; 203 | color:#927c67; 204 | margin: 0 auto; 205 | padding-left: 0 !important; 206 | 207 | 208 | } 209 | 210 | 211 | 212 | header nav ul { 213 | border: none; 214 | } 215 | 216 | .sf-menu{display:none !important; float: none;} 217 | 218 | #mm0{ 219 | font:12px/15px Arial, Helvetica, sans-serif; 220 | color:#202020; 221 | width:100%; 222 | margin: 0 auto; 223 | float: none; 224 | outline: none; 225 | border:2px solid #fff; 226 | } 227 | 228 | 229 | } 230 | -------------------------------------------------------------------------------- /static/css/touchTouch.css: -------------------------------------------------------------------------------- 1 | /* The gallery overlay */ 2 | 3 | #galleryOverlay{ 4 | width:100%; 5 | height:100%; 6 | position:fixed; 7 | top:0; 8 | left:0; 9 | opacity:0; 10 | z-index:100000; 11 | background-color:#222; 12 | background-color:rgba(0,0,0,0.8); 13 | overflow:hidden; 14 | display:none; 15 | 16 | -moz-transition:opacity 1s ease; 17 | -webkit-transition:opacity 1s ease; 18 | transition:opacity 1s ease; 19 | } 20 | 21 | /* This class will trigger the animation */ 22 | 23 | #galleryOverlay.visible{ 24 | opacity:1; 25 | } 26 | 27 | #gallerySlider{ 28 | height:100%; 29 | 30 | left:0; 31 | top:0; 32 | 33 | width:100%; 34 | white-space: nowrap; 35 | position:absolute; 36 | 37 | -moz-transition:left 0.4s ease; 38 | -webkit-transition:left 0.4s ease; 39 | transition:left 0.4s ease; 40 | } 41 | 42 | #gallerySlider .placeholder{ 43 | background: url("../images/preloader.gif") no-repeat center center; 44 | height: 100%; 45 | line-height: 1px; 46 | text-align: center; 47 | width:100%; 48 | display:inline-block; 49 | } 50 | 51 | /* The before element moves the 52 | * image halfway from the top */ 53 | 54 | #gallerySlider .placeholder:before{ 55 | content: ""; 56 | display: inline-block; 57 | height: 50%; 58 | width: 1px; 59 | margin-right:-1px; 60 | } 61 | 62 | #gallerySlider .placeholder img{ 63 | display: inline-block; 64 | max-height: 80%; 65 | max-width: 80%; 66 | width: auto !important; 67 | vertical-align: middle; 68 | } 69 | 70 | #gallerySlider.rightSpring{ 71 | -moz-animation: rightSpring 0.3s; 72 | -webkit-animation: rightSpring 0.3s; 73 | } 74 | 75 | #gallerySlider.leftSpring{ 76 | -moz-animation: leftSpring 0.3s; 77 | -webkit-animation: leftSpring 0.3s; 78 | } 79 | 80 | /* Firefox Keyframe Animations */ 81 | 82 | @-moz-keyframes rightSpring{ 83 | 0%{ margin-left:0px;} 84 | 50%{ margin-left:-30px;} 85 | 100%{ margin-left:0px;} 86 | } 87 | 88 | @-moz-keyframes leftSpring{ 89 | 0%{ margin-left:0px;} 90 | 50%{ margin-left:30px;} 91 | 100%{ margin-left:0px;} 92 | } 93 | 94 | /* Safari and Chrome Keyframe Animations */ 95 | 96 | @-webkit-keyframes rightSpring{ 97 | 0%{ margin-left:0px;} 98 | 50%{ margin-left:-30px;} 99 | 100%{ margin-left:0px;} 100 | } 101 | 102 | @-webkit-keyframes leftSpring{ 103 | 0%{ margin-left:0px;} 104 | 50%{ margin-left:30px;} 105 | 100%{ margin-left:0px;} 106 | } 107 | 108 | /* Arrows */ 109 | 110 | #prevArrow,#nextArrow{ 111 | border:none; 112 | text-decoration:none; 113 | background:url('../images/arrowws.png') no-repeat; 114 | opacity:0.5; 115 | cursor:pointer; 116 | position:absolute; 117 | width:43px; 118 | height:58px; 119 | 120 | top:50%; 121 | margin-top:-29px; 122 | 123 | -moz-transition:opacity 0.2s ease; 124 | -webkit-transition:opacity 0.2s ease; 125 | transition:opacity 0.2s ease; 126 | } 127 | 128 | #prevArrow:hover, #nextArrow:hover{ 129 | opacity:1; 130 | } 131 | 132 | #prevArrow{ 133 | background-position:left top; 134 | left:40px; 135 | } 136 | 137 | #nextArrow{ 138 | background-position:right top; 139 | right:40px; 140 | } 141 | -------------------------------------------------------------------------------- /static/demo.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/images/DTU-Campus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/DTU-Campus.jpg -------------------------------------------------------------------------------- /static/images/a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/a.jpg -------------------------------------------------------------------------------- /static/images/arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/arrows.png -------------------------------------------------------------------------------- /static/images/arrowws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/arrowws.png -------------------------------------------------------------------------------- /static/images/big1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/big1.jpg -------------------------------------------------------------------------------- /static/images/big2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/big2.jpg -------------------------------------------------------------------------------- /static/images/big3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/big3.jpg -------------------------------------------------------------------------------- /static/images/big4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/big4.jpg -------------------------------------------------------------------------------- /static/images/big5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/big5.jpg -------------------------------------------------------------------------------- /static/images/big6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/big6.jpg -------------------------------------------------------------------------------- /static/images/big7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/big7.jpg -------------------------------------------------------------------------------- /static/images/big8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/big8.jpg -------------------------------------------------------------------------------- /static/images/big9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/big9.jpg -------------------------------------------------------------------------------- /static/images/camera-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/camera-loader.gif -------------------------------------------------------------------------------- /static/images/capt_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/capt_bg.png -------------------------------------------------------------------------------- /static/images/comm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/comm.jpg -------------------------------------------------------------------------------- /static/images/cost.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/cost.jpg -------------------------------------------------------------------------------- /static/images/cost1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/cost1.jpg -------------------------------------------------------------------------------- /static/images/dtu2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/dtu2.jpg -------------------------------------------------------------------------------- /static/images/dtu3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/dtu3.png -------------------------------------------------------------------------------- /static/images/dtu4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/dtu4.jpg -------------------------------------------------------------------------------- /static/images/dtutoramaecl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/dtutoramaecl.png -------------------------------------------------------------------------------- /static/images/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/icon1.png -------------------------------------------------------------------------------- /static/images/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/icon2.png -------------------------------------------------------------------------------- /static/images/icon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/icon3.png -------------------------------------------------------------------------------- /static/images/icon4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/icon4.png -------------------------------------------------------------------------------- /static/images/icon5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/icon5.jpg -------------------------------------------------------------------------------- /static/images/imgonline-com-ua-resize-ldHHNkkIfP5vwUWa (1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/imgonline-com-ua-resize-ldHHNkkIfP5vwUWa (1).jpg -------------------------------------------------------------------------------- /static/images/loc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/loc.jpg -------------------------------------------------------------------------------- /static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/logo.png -------------------------------------------------------------------------------- /static/images/magnifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/magnifier.png -------------------------------------------------------------------------------- /static/images/menu_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/menu_bg.png -------------------------------------------------------------------------------- /static/images/nsit1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/nsit1.jpg -------------------------------------------------------------------------------- /static/images/nsit2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/nsit2.jpg -------------------------------------------------------------------------------- /static/images/nsit3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/nsit3.jpg -------------------------------------------------------------------------------- /static/images/nsit4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/nsit4.jpg -------------------------------------------------------------------------------- /static/images/page1_img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page1_img1.jpg -------------------------------------------------------------------------------- /static/images/page1_img2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page1_img2.jpg -------------------------------------------------------------------------------- /static/images/page1_img3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page1_img3.jpg -------------------------------------------------------------------------------- /static/images/page2_img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page2_img1.jpg -------------------------------------------------------------------------------- /static/images/page3_img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page3_img1.jpg -------------------------------------------------------------------------------- /static/images/page3_img2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page3_img2.jpg -------------------------------------------------------------------------------- /static/images/page3_img3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page3_img3.jpg -------------------------------------------------------------------------------- /static/images/page3_img4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page3_img4.jpg -------------------------------------------------------------------------------- /static/images/page3_img5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page3_img5.jpg -------------------------------------------------------------------------------- /static/images/page3_img6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page3_img6.jpg -------------------------------------------------------------------------------- /static/images/page3_img7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page3_img7.jpg -------------------------------------------------------------------------------- /static/images/page3_img8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page3_img8.jpg -------------------------------------------------------------------------------- /static/images/page3_img9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page3_img9.jpg -------------------------------------------------------------------------------- /static/images/page4_img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page4_img1.jpg -------------------------------------------------------------------------------- /static/images/page4_img3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page4_img3.jpg -------------------------------------------------------------------------------- /static/images/page4_img4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page4_img4.jpg -------------------------------------------------------------------------------- /static/images/page4_img5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page4_img5.jpg -------------------------------------------------------------------------------- /static/images/page4_img6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page4_img6.jpg -------------------------------------------------------------------------------- /static/images/page4_img7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page4_img7.jpg -------------------------------------------------------------------------------- /static/images/page4_img8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page4_img8.jpg -------------------------------------------------------------------------------- /static/images/page4_img9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/page4_img9.jpg -------------------------------------------------------------------------------- /static/images/preloader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/preloader.gif -------------------------------------------------------------------------------- /static/images/prevnext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/prevnext.png -------------------------------------------------------------------------------- /static/images/quotes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/quotes.png -------------------------------------------------------------------------------- /static/images/serv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/serv.jpg -------------------------------------------------------------------------------- /static/images/serv1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/serv1.jpg -------------------------------------------------------------------------------- /static/images/slide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/slide.jpg -------------------------------------------------------------------------------- /static/images/slide1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/slide1.jpg -------------------------------------------------------------------------------- /static/images/slide2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/slide2.jpg -------------------------------------------------------------------------------- /static/images/spacer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtmegaBuzz/BookCab/cda69e1cec9df35f03ef4b8bf3b715d41c065511/static/images/spacer.png -------------------------------------------------------------------------------- /static/js/Web3Payments.js: -------------------------------------------------------------------------------- 1 | 2 | const metamask = window.ethereum 3 | const metaMaskErr = "Metamask is required for payments"; 4 | let oneEthWei = 1000000000000000000n 5 | let web3js = new Web3(metamask); 6 | let minimumEthTransfer = 0.01 7 | let ContractABI = [ 8 | { 9 | "inputs": [ 10 | { 11 | "internalType": "string", 12 | "name": "bookingHash", 13 | "type": "string" 14 | } 15 | ], 16 | "name": "pay", 17 | "outputs": [], 18 | "stateMutability": "payable", 19 | "type": "function" 20 | }, 21 | { 22 | "inputs": [ 23 | { 24 | "internalType": "string", 25 | "name": "_secretKey", 26 | "type": "string" 27 | } 28 | ], 29 | "name": "setSecretKey", 30 | "outputs": [], 31 | "stateMutability": "nonpayable", 32 | "type": "function" 33 | }, 34 | { 35 | "inputs": [ 36 | { 37 | "internalType": "string", 38 | "name": "_secretkey", 39 | "type": "string" 40 | }, 41 | { 42 | "internalType": "address", 43 | "name": "transferTo", 44 | "type": "address" 45 | } 46 | ], 47 | "name": "transferFunds", 48 | "outputs": [], 49 | "stateMutability": "nonpayable", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [], 54 | "stateMutability": "nonpayable", 55 | "type": "constructor" 56 | }, 57 | { 58 | "inputs": [ 59 | { 60 | "internalType": "string", 61 | "name": "bookingHash", 62 | "type": "string" 63 | } 64 | ], 65 | "name": "getBooking", 66 | "outputs": [ 67 | { 68 | "internalType": "uint256", 69 | "name": "", 70 | "type": "uint256" 71 | } 72 | ], 73 | "stateMutability": "view", 74 | "type": "function" 75 | }, 76 | { 77 | "inputs": [], 78 | "name": "getTotalBalance", 79 | "outputs": [ 80 | { 81 | "internalType": "uint256", 82 | "name": "", 83 | "type": "uint256" 84 | } 85 | ], 86 | "stateMutability": "view", 87 | "type": "function" 88 | } 89 | ] 90 | 91 | const contractAddress = "0x8874E50bd62D1D7F46c8EFbBc767F17e5Bf5C3e9"; 92 | const contract = new web3js.eth.Contract(ContractABI,contractAddress); 93 | 94 | 95 | async function getInrToWei(bookingCost){ 96 | 97 | const resp = await fetch("https://api.coinbase.com/v2/exchange-rates?currency=ETH"); 98 | const exchangeRates = await resp.json(); 99 | return web3js.utils.toWei(((bookingCost / exchangeRates.data.rates.INR) + minimumEthTransfer).toString(),"ether"); 100 | 101 | 102 | } 103 | 104 | async function payBooking(bookingHash,bookingCost){ 105 | 106 | 107 | const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); 108 | let bookingCostWei = await getInrToWei(bookingCost); 109 | 110 | let transactionParam = { 111 | from: accounts[0], 112 | value: "0x"+"100".toString(16), 113 | gas: "3000000".toString(16), 114 | gasPrice: "3000000".toString(16) 115 | } 116 | 117 | try{ 118 | transaction = await contract.methods.pay(bookingHash).send(transactionParam); 119 | success_booking_url = "http://"+window.location.host+`/booking-payment/${bookingHash}` 120 | console.log(success_booking_url) 121 | await fetch(success_booking_url); 122 | location.reload(true); 123 | 124 | } catch{ 125 | console.error("transaction failed"); 126 | } 127 | } 128 | 129 | if (metamask === undefined){ 130 | window.alert(metaMaskErr); 131 | $("#pay").css({'background-color':"grey"}); 132 | $("#pay").click(()=>{ 133 | window.alert(metaMaskErr); 134 | }); 135 | } 136 | 137 | -------------------------------------------------------------------------------- /static/js/html5shiv.js: -------------------------------------------------------------------------------- 1 | /* 2 | HTML5 Shiv v3.6.2pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | (function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); 5 | a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; 6 | c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| 7 | "undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",version:"3.6.2pre",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment(); 8 | for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d
"); 6 | }) 7 | $(".maxheight1").each(function(){ 8 | $(this).contents().wrapAll("
"); 9 | }) 10 | $(".maxheight2").each(function(){ 11 | $(this).contents().wrapAll("
"); 12 | }) 13 | }) 14 | /*add event*/ 15 | $(window).bind("resize", height_handler).bind("load", height_handler) 16 | function height_handler(){ 17 | if($(window).width()>767){ 18 | $(".maxheight").equalHeights(); 19 | }else{ 20 | $(".maxheight").css({'height':'auto'}); 21 | } 22 | if($(window).width()>767){ 23 | $(".maxheight1").equalHeights(); 24 | }else{ 25 | $(".maxheight1").css({'height':'auto'}); 26 | } 27 | if($(window).width()>767){ 28 | $(".maxheight2").equalHeights(); 29 | }else{ 30 | $(".maxheight2").css({'height':'auto'}); 31 | } 32 | } 33 | /*glob function*/ 34 | (function($){ 35 | $.fn.equalHeights=function(minHeight,maxHeight){ 36 | tallest=(minHeight)?minHeight:0; 37 | this.each(function(){ 38 | if($(">.box_inner", this).outerHeight()>tallest){ 39 | tallest=$(">.box_inner", this).outerHeight() 40 | } 41 | }); 42 | if((maxHeight)&&tallest>maxHeight) tallest=maxHeight; 43 | return this.each(function(){$(this).height(tallest)}) 44 | } 45 | })(jQuery) 46 | -------------------------------------------------------------------------------- /static/js/jquery.mobilemenu.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | 3 | //plugin's default options 4 | var settings = { 5 | prependTo: 'nav', //insert at top of page by default 6 | switchWidth: 768, //width at which to switch to select, and back again 7 | topOptionText: 'Select a page:' //default "unselected" state 8 | }, 9 | 10 | menuCount = 0, //used as a unique index for each menu if no ID exists 11 | uniqueLinks = []; //used to store unique list items for combining lists 12 | 13 | //go to page 14 | function goTo(url){document.location.href = url;} 15 | 16 | //does menu exist? 17 | function menuExists(){return ($('.mnav').length) ? true : false;} 18 | 19 | //validate selector's matched list(s) 20 | function isList($this){ 21 | var pass = true; 22 | $this.each(function(){ 23 | if(!$(this).is('ul') && !$(this).is('ol')){ 24 | pass=false; 25 | } 26 | }); 27 | return pass; 28 | }//isList() 29 | 30 | //function to decide if mobile or not 31 | function isMobile(){return ($(document).width() < settings.switchWidth);} 32 | 33 | //function to get text value of element, but not it's children 34 | function getText($item){return $.trim($item.clone().children('ul, ol').remove().end().text());} 35 | 36 | //function to check if URL is unique 37 | function isUrlUnique(url){return ($.inArray(url, uniqueLinks) === -1) ? true : false;} 38 | 39 | //function to create options in the select menu 40 | function createOption($item, $container, text){ 41 | //if no text param is passed, use list item's text, otherwise use settings.groupPageText 42 | var $selected='', $disabled='', $sel_text=''; 43 | 44 | if ($item.hasClass('current')) $selected='selected'; 45 | if ($item.hasClass('disabled')) { 46 | if ($('.current').length) $disabled='disabled'; 47 | else $disabled='selected'; 48 | } 49 | 50 | $sel_text=$.trim(getText($item)); 51 | $sel_text = $sel_text.replace('»', ''); 52 | if ($item.parent('ul ul').length) $sel_text = ' – ' + $sel_text; 53 | if ($item.parent('ul ul ul').length) $sel_text = '– ' + $sel_text; 54 | if ($item.parent('ul ul ul ul').length) $sel_text = '– ' + $sel_text; 55 | 56 | if(!text){$('').appendTo($container);} 57 | else {$('').appendTo($container);} 58 | }//createOption() 59 | 60 | //function to create submenus 61 | function createGroup($group, $container){ 62 | //loop through each sub-nav list 63 | $group.children('ul, ol').each(function(){ 64 | $(this).children('li').each(function(){ 65 | createOption($(this), $container); 66 | 67 | $(this).each(function(){ 68 | var $li_ch = $(this), 69 | $container_ch = $container; 70 | createGroup($li_ch, $container_ch); 71 | }); 72 | }); 73 | }); 74 | 75 | }//createGroup() 76 | 77 | //function to create to insert into the page 80 | var $select = $(' 62 | 63 | 64 | 65 | 66 |
Hey, I'm here at the Top-right
67 | 68 | 69 | -------------------------------------------------------------------------------- /templates/contact.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Contact Us 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 44 | 45 | 46 |
47 | 48 | 49 | {%include 'navbar.html'%} 50 | 51 |
52 |
53 | 54 |
55 |

Find Us

56 |
57 |
58 |
59 |
60 |
61 |
62 |

Contact Info

63 |
64 |
This website is designed for project and research work only and is not meant for any personal or commercial purposes.
65 |

Use link if you need any help or have any queries regarding the project.

66 |
67 |

Address:

68 |
69 |
70 |
71 |
NBNSSOE Pune,
72 | S. No. 10/1, Off, Sinhgad Rd, Ambegaon BK
73 | Maharashtra - 411041. 74 |
75 |
Telephone: +91xxxxxxxxxxx
76 |
Mobile No.: +91xxxxxxxxxxx
77 |
E-mail: registrar@nbnssoe.ac.in
78 |
79 |
80 |
81 |
82 |
83 |

Contact Form

84 |
85 |
86 |
Contact form submitted
87 |
88 | 93 | 98 | 103 | 108 |
109 |
110 |
111 | Send 112 | Clear 113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | 122 |
123 |
124 |
125 |
Call Us: + 91xxxxxxxxxx
126 |
127 | 128 | 129 | 130 |
131 |
132 |
133 |
BookTaxi
134 | © 2021 | Privacy Policy
Website designed for One Source Multiple Destination(osmd) 135 |
136 |
137 |
138 |
139 |
140 | 141 | -------------------------------------------------------------------------------- /templates/detail-group.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {%block title%} Booking {% endblock %} 3 | 4 | {% block js %} 5 | 6 | 7 | 8 | {% endblock %} 9 | 10 | {% block css %} 11 | 17 | {% endblock %} 18 | 19 | {% block body %} 20 | 21 |
22 |
23 |
24 |
25 |

Services Overview

26 |
27 | 28 | 29 | 30 |
31 |
32 | 33 |
34 |
35 |

Your Bookings

36 |
37 |
38 |
39 | 40 | 41 | 42 | 43 | 46 | 49 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | {%for booking in grp_bookings%} 63 | 64 | 65 | 71 | 77 | 85 | 93 | 94 | 95 | {%endfor%} 96 | 97 |
44 |
Destination
45 |
47 |
Person
48 |
50 |
Fare
51 |
53 |
Status
54 |
66 |
67 | 68 |
{{booking.destination}}
69 |
70 |
72 | 73 |
{{booking.user.email}}
74 | 75 | 76 |
78 | {%if booking.status == 1%} 79 |
₹{{booking.cost}}
80 | {%else%} 81 |
0
82 | 83 | {%endif%} 84 |
86 | {%if booking.status == 1%} 87 |
Cab Booked
88 | {%else%} 89 |
ongoing
90 | {%endif%} 91 | 92 |
98 |
99 |
100 | 101 |
102 |
103 |
104 |
105 | 106 |
107 | 108 |
109 |
110 | 111 | 112 | 113 |
114 |
115 | 116 | 117 | 155 |
156 |
157 | 158 | 159 | 160 | {% endblock %} 161 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %} Home {% endblock %} 4 | 5 | 6 | {% block body %} 7 |
8 |
9 |
10 |
11 |
12 | 13 |
14 |
15 |
16 |
17 | 29 |
30 |
31 | 42 |
43 |
44 | 55 |
56 |
57 |
58 | 59 | 60 |
61 |
62 |
63 |

Book a cab

64 |
65 | {{ form.hidden_tag() }} 66 |
67 | {{ form.destination.label }} 68 | {{ form.destination(id="destination-autocomplete") }} 69 | 76 |
77 | 78 |
79 | {{ form.time.label }} 80 |
81 | {{ form.time() }} 82 |
83 |
84 | Date 85 | 89 |
90 | 91 | 92 | 93 | {% for message in get_flashed_messages() %} 94 |

{{message}}

95 | {% endfor %} 96 | 97 |
98 |
99 |
100 |
Book Cab
101 |
Live Location
102 |
Share stories
103 |
104 |
105 |
106 |
107 | 108 | 109 | {% endblock %} 110 | 111 | 112 | {% block jsend %} 113 | 114 | {% endblock %} -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {%block title%} Login {% endblock %} 3 | 4 | {% block body %} 5 | 6 |
7 |
8 |
9 |

Login

10 |
11 | {{ form.hidden_tag() }} 12 |
13 |
14 | {{ form.email.label }} 15 | {{ form.email() }} 16 |
17 |
18 |
19 |
20 |
21 | {{ form.password.label }} 22 | {{ form.password() }} 23 |
24 |
25 |
26 | {{ form.submit() }} 27 |
28 | {% for message in get_flashed_messages() %} 29 |

{{message}}

30 | {% endfor %} 31 |
32 |
33 |
34 |
35 |
Book Cab
36 |
Live Location
37 |
Share stories
38 |
39 |
40 |
41 |
42 | 43 | 44 | {% endblock %} -------------------------------------------------------------------------------- /templates/navbar.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 25 |
26 |
27 |

28 | 29 | 30 | new logo 31 | 32 |

33 |
34 |
35 |
36 |
-------------------------------------------------------------------------------- /templates/register.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %} Register {% endblock %} 4 | 5 | 6 | {% block body %} 7 |
8 |
9 |
10 |

Register

11 |
12 | {{ form.hidden_tag() }} 13 |
14 | {{ form.name.label }} 15 | {{ form.name() }} 16 |
17 |
18 | {{ form.phone_number.label }} 19 | {{ form.phone_number() }} 20 |
21 |
22 | {{ form.email.label }} 23 | {{ form.email() }} 24 |
25 |
26 |
27 | {{ form.password.label }} 28 | {{ form.password() }} 29 |
30 |
31 | {{ form.submit(class="btn") }} 32 |
33 | {% for message in get_flashed_messages() %} 34 |

{{message}}

35 | {% endfor %} 36 | 37 |
38 |
39 |
40 |
41 |
Book Cab
42 |
Live Location
43 |
Share stories
44 |
45 |
46 |
47 |
48 | 49 | 50 | {% endblock %} -------------------------------------------------------------------------------- /templates/services.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %} Services {% endblock %} 4 | 5 | {% block js %} 6 | 7 | {% endblock %} 8 | 9 | {% block body %} 10 | 11 |
12 |
13 |
14 |
15 |

Services Overview

16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 | 26 |
27 |
28 |

Your Bookings

29 |
30 |
31 |
32 | 33 | 34 | 35 | 36 | 39 | 42 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | {%if bookings%} 54 | 55 | {%for booking in bookings%} 56 | 57 | 58 | 77 | 85 | 94 | 109 | 110 | 111 | 112 | {%endfor%} 113 | 114 | {%else%} 115 |
116 |

No current bookings

117 |
118 | {%endif%} 119 | 120 | 121 | 122 |
37 |
Destination
38 |
40 |
Group
41 |
43 |
Fare
44 |
46 |
Status
47 |
59 |
60 | 70 | {%if booking.status == 1 or booking.status == 2%} 71 | {{booking.destination}} 72 | {%else%} 73 | {{booking.destination}} 74 | {%endif%} 75 |
76 |
78 | {%if booking.status == 1%} 79 |
Accepted
80 | {%else%} 81 |
searching groups
82 | {%endif%} 83 | 84 |
86 | {%if booking.status == 1%} 87 |
₹{{booking.cost}}
88 | {%elif booking.status == 2%} 89 |
PAID
90 | {%else%} 91 |
0
92 | {%endif%} 93 |
95 | {%if booking.status == 0%} 96 |
ongoing
97 | {%elif booking.status == 1%} 98 | 99 | 104 | {%elif booking.status == 2%} 105 |
Cab Booked
106 | {%endif%} 107 | 108 |
123 |
124 |
125 |
126 |
127 |
128 | 129 |
130 |
131 |
132 | page4_img4 133 |
134 |
Fastest route.
135 |
136 | Aim of this project is to provide passengers with the fastest paths. This is done through a 137 | dynamic programming based approach. 138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | cost1 146 |
147 |
Minimum Cost
148 |
149 | Another aim of this project is to make rides cost effective for all the passengers. We have 150 | designed this website to demonstrate the same. 151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | serv1 159 |
160 |
Communicate with others
161 |
162 | A communication platform is embedded within the project. A group chat thread will be created 163 | for all the persons within the same cab. 164 |
165 |
166 |
167 |
168 | 169 |
170 |
171 |
172 | 173 | 174 | 175 | {% endblock %} -------------------------------------------------------------------------------- /tests/functional/test_login.py: -------------------------------------------------------------------------------- 1 | from backend import create_app 2 | 3 | 4 | def test_login_page(): 5 | """ 6 | Given a Flask application configured for tesing 7 | WHEN the auth/login page is requested (GET) 8 | THEN check if the response is contains email and password fields 9 | 10 | WHEN the auth/register page is requested (POST) 11 | THEN check if the user is created 12 | """ 13 | 14 | flask_app = create_app(testing=True) 15 | 16 | with flask_app.test_client() as test_client: 17 | 18 | response = test_client.get('/auth/login') 19 | 20 | assert response.status_code == 200 21 | assert b'Login' in response.data 22 | assert b'Email' in response.data 23 | assert b'Password' in response.data 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/functional/test_register.py: -------------------------------------------------------------------------------- 1 | from backend import create_app 2 | 3 | def test_register_page(): 4 | """ 5 | Given a Flask application configured for tesing 6 | WHEN the auth/register page is requested (GET) 7 | THEN check if the response contains register,name,phone_number,email and password fields 8 | 9 | WHEN the auth/register page is requested (POST) 10 | THEN check if the user is created 11 | """ 12 | 13 | flask_app = create_app(testing=True) 14 | 15 | with flask_app.test_client() as test_client: 16 | 17 | response = test_client.get('/auth/register') 18 | 19 | assert response.status_code == 200 20 | assert b'Register' in response.data 21 | assert b'Name' in response.data 22 | assert b'Phone Number' in response.data 23 | assert b'Email' in response.data 24 | assert b'Password' in response.data 25 | 26 | -------------------------------------------------------------------------------- /tests/unit/test_models.py: -------------------------------------------------------------------------------- 1 | from backend.models import User,Booking 2 | 3 | 4 | def test_new_user(): 5 | """ 6 | Given a User modal 7 | WHEN a new User is created 8 | THEN check the name, email, phone_number and password_hashed fields are defined correctly 9 | """ 10 | 11 | user = User( 12 | name = "testuser", 13 | phone_number = "+919583750310", # fake number 14 | email = "testemail@gmail.com", 15 | password = "testpassword" 16 | ) 17 | assert user.email == 'testemail@gmail.com' 18 | assert user.name == 'testuser' 19 | assert user.phone_number == '+919583750310' 20 | assert user.password == 'testpassword' 21 | 22 | # this test will always fails cause password is hashed in register view so tested for no hash pass 23 | 24 | 25 | 26 | def test_new_bookings(): 27 | """ 28 | Given a Booking modal 29 | WHEN a new Booking is created 30 | THEN check the destination, status, cost, distance is defined correctly 31 | """ 32 | 33 | booking = Booking( 34 | destination = "new delhi", 35 | status = 0, 36 | cost = 100, 37 | distance = 1000 38 | ) 39 | 40 | assert booking.destination == 'new delhi' 41 | assert booking.status == 0 42 | assert booking.cost == 100 43 | assert booking.distance == 1000 --------------------------------------------------------------------------------