From d971d5d5222647971b9df74aad5f653124a5614f Mon Sep 17 00:00:00 2001 From: paulmataruso Date: Wed, 6 Nov 2024 19:09:33 +0000 Subject: [PATCH] First Upload --- README.md | 63 + bgp-dashboard.png | Bin 0 -> 150492 bytes bgp_attributes.py | 33 + docker-compose.yml | 23 + flask/Dockerfile | 31 + flask/app/Stats.py | 174 + flask/app/bgp.py | 237 ++ flask/app/constants.py | 31 + flask/app/functions.py | 145 + flask/app/requirements.txt | 9 + flask/app/static/css/custom.css | 3989 +++++++++++++++++++ flask/app/static/js/jquery.sparkline.min.js | 6 + flask/app/templates/bgp.html | 569 +++ flask/app/uwsgi.ini | 16 + flask/nginx/flask.conf | 18 + flask/supervisor/supervisord.conf | 8 + gobgp/Dockerfile | 26 + gobgp/entrypoint.sh | 3 + gobgp/gobgpd.conf | 15 + gobgp/requirements.txt | 3 + gobgp/startup.sh | 7 + gobgp_to_mongo.py | 200 + 22 files changed, 5606 insertions(+) create mode 100644 README.md create mode 100644 bgp-dashboard.png create mode 100644 bgp_attributes.py create mode 100755 docker-compose.yml create mode 100644 flask/Dockerfile create mode 100644 flask/app/Stats.py create mode 100644 flask/app/bgp.py create mode 100644 flask/app/constants.py create mode 100644 flask/app/functions.py create mode 100644 flask/app/requirements.txt create mode 100644 flask/app/static/css/custom.css create mode 100644 flask/app/static/js/jquery.sparkline.min.js create mode 100644 flask/app/templates/bgp.html create mode 100644 flask/app/uwsgi.ini create mode 100644 flask/nginx/flask.conf create mode 100644 flask/supervisor/supervisord.conf create mode 100755 gobgp/Dockerfile create mode 100644 gobgp/entrypoint.sh create mode 100755 gobgp/gobgpd.conf create mode 100644 gobgp/requirements.txt create mode 100644 gobgp/startup.sh create mode 100755 gobgp_to_mongo.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..971c45a --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +BGP Dashboard +============= + +A "realtime" web view of your BGP network + +- Who do I peer with? +- How many routes do I receive from my peers? +- Who do I use for tranist? +- What AS path does a prefix take out of my network? +- How many routes and autonomous systems do I see? +- BGP Looking Glass (IPv4/IPv6/ASN) + + +How it works +--------- +> This is beta code. +- BGP peering session using GoBGP +- GoBGP pipes BGP information into MongoDB +- Flask App queries MongoDB to build website and JSON API + +###### This project uses three Docker containers +- GoBGP ([osrg/gobgp](https://hub.docker.com/r/osrg/gobgp/)) +- MongoDB ([mongo](https://hub.docker.com/_/mongo/)) +- Flask ([docker-flask](https://hub.docker.com/r/p0bailey/docker-flask/)) + +###### GoBGP +The GoBGP container serves two functions: +- Peer with the "real" network + - Configure [gobgpd.conf](https://github.com/rhicks/bgp-dash/blob/master/gobgp/gobgpd.conf) to peer with the real network. + - Only IPv4-Unicast and IPv6-Unicast supported at this time. +- Pass BGP updates into BGP + - The [gobgp_to_mongo.py](https://github.com/rhicks/bgp-dash/blob/master/gobgp_to_mongo.py) script pipes the JSON updates from GoBGP into the MongoDB container + +###### MongoDB +- Mongo receives JSON updates from the GoBGP container +- The Flask App queries Mongo for relevant information + +###### Flask +- Flask presents a Dashboard for realtime BGP updates +- A JSON API is used on the backend to support the frontend and display Looking Glass queries + + +Screenshot +--------- +![screenshot](bgp-dashboard.png) + + +Install +--------- +``` +$ git clone https://github.com/NetDevUG/bgp-dashboard.git +$ cd bgp-dashboard +$ # modify ./gobgp/gobgpd.conf to peer with your network +$ # modify ./flask/app/constants.py globals to use your ASN and BGP communities +$ docker compose build +$ docker compose up (watch the log to verify BGP peeering is established) +``` + + +Todo +--------- +- Update gobgp +- Update Python Dependencys diff --git a/bgp-dashboard.png b/bgp-dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..a6b30f7ee44bc762e21168f2867d6977ae13e03f GIT binary patch literal 150492 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%0Db%J0gM5S^w>E%7OT_|#XU&dduVcYbY3+0<4E!5 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 G`F{ZSUk9ZC literal 0 HcmV?d00001 diff --git a/bgp_attributes.py b/bgp_attributes.py new file mode 100644 index 0000000..e585971 --- /dev/null +++ b/bgp_attributes.py @@ -0,0 +1,33 @@ +# BGP Attributes +PREFIX = 0 +ORIGIN = 1 +AS_PATH = 2 +NEXT_HOP = 3 +MULTI_EXIT_DISC = 4 +LOCAL_PREF = 5 +ATOMIC_AGGREGATE = 6 +AGGREGATOR = 7 +COMMUNITY = 8 +ORIGINATOR_ID = 9 +CLUSTER_LIST = 10 +DPA = 11 +ADVERTISER = 12 +CLUSTER_ID = 13 +MP_REACH_NLRI = 14 +MP_UNREACH_NLRI = 15 +EXTENDED_COMMUNITIES = 16 +LARGE_COMMUNITIES = 32 +# +WITHDRAWAL = 11 +AGE = 12 +# +ORIGIN_CODE = { + 0: 'IGP', + 1: 'EGP', + 2: 'INCOMPLETE' +} +# BGP UPDATE CODES +OPEN = 1 +UPDATE = 2 +NOTIFICATION = 3 +KEEPALIVE = 4 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100755 index 0000000..579c239 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +services: + gobgp: + build: ./gobgp + ports: + - "172.16.1.66:179:179" + volumes: + - .:/var/tmp + restart: always + + mongodb: + image: mongo:latest + expose: + - 27017 + volumes: + - ./db:/data/db + + flask: + build: ./flask + ports: + - 80:80 + volumes: + - ./flask/app:/var/www/app + - ./flask/app/log:/var/log/uwsgi/app diff --git a/flask/Dockerfile b/flask/Dockerfile new file mode 100644 index 0000000..d5f8bd6 --- /dev/null +++ b/flask/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:24.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y \ + python3 \ + python3-pip \ + python3-venv \ + uwsgi-plugin-python3 \ + nginx \ + supervisor && \ + echo 'Etc/UTC' >/etc/timezone && \ + apt-get install -y --reinstall tzdata && \ + rm -rf /var/lib/apt/lists/* + +COPY nginx/flask.conf /etc/nginx/sites-available/ +COPY supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY app/requirements.txt /tmp/requirements.txt + +RUN python3 -m venv venv && chmod +x venv +RUN mkdir -p /var/log/nginx/app /var/log/uwsgi/app /var/log/supervisor /var/www/app && \ + rm /etc/nginx/sites-enabled/default && \ + ln -s /etc/nginx/sites-available/flask.conf /etc/nginx/sites-enabled/flask.conf && \ + echo "daemon off;" >> /etc/nginx/nginx.conf && \ + . venv/bin/activate && \ + pip3 install -r /tmp/requirements.txt && \ + chown -R www-data:www-data /var/www/app && \ + chown -R www-data:www-data /var/log + +CMD ["/usr/bin/supervisord"] diff --git a/flask/app/Stats.py b/flask/app/Stats.py new file mode 100644 index 0000000..ba47f0c --- /dev/null +++ b/flask/app/Stats.py @@ -0,0 +1,174 @@ +import constants as C +import dns.resolver +import time +from collections import Counter +from flask import jsonify +from itertools import islice +from pymongo import MongoClient +from functions import asn_name_query + + +class Stats(object): + def __init__(self): + self.db = self.db_connect() + self.peer_counter = 0 + self.ipv4_table_size = 0 + self.ipv6_table_size = 0 + self.nexthop_ip_counter = 0 + self.avg_as_path_length = 0 + self.top_n_peers = [] + self.cidr_breakdown = [] + self.communities = [] + self.peers = [] + self.customers = [] + self.customer_count = 0 + self.customer_ipv4_prefixes = 0 + self.customer_ipv6_prefixes = 0 + self.timestamp = self.epoch_to_date(time.time()) + + # @property + # def peer_counter(self): + # return self._peer_counter + + # @peer_counter.setter + # def peer_counter(self): + # self._peer_counter = len(self.db['bgp'].distinct('nexthop_asn', {'active': True})) + + def db_connect(self): + """Return a connection to the Mongo Database.""" + client = MongoClient(host='mongodb') + return client.bgp + + def take(self, n, iterable): + """Return first n items of the iterable as a list.""" + return list(islice(iterable, n)) + + def peer_count(self): + """Return the number of directly connected ASNs.""" + return len(self.db['bgp'].distinct('nexthop_asn', {'active': True})) + + def prefix_count(self, version): + """Given the IP version, return the number of prefixes in the database.""" + return self.db['bgp'].count_documents({'ip_version': version, 'active': True}) + + def nexthop_ip_count(self): + """Return the number of unique next hop IPv4 and IPv6 addresses.""" + return len(self.db['bgp'].distinct('nexthop', {'active': True})) + + def epoch_to_date(self, epoch): + """Given an *epoch* time stamp, return a human readable equivalent.""" + return time.strftime('%Y-%m-%d %H:%M:%S %Z', time.gmtime(epoch)) + + def get_list_of(self, customers=False, peers=False, community=C.CUSTOMER_BGP_COMMUNITY): + """Return a list of prefix dictionaries. Specify which type of prefix to + return by setting *customers* or *peers* to True.""" + if peers: + query_results = {prefix['nexthop_asn'] for prefix in self.db['bgp'].find({'active': True})} + else: # customers + query_results = {prefix['nexthop_asn'] for prefix in + self.db['bgp'].find({'communities': community, 'active': True})} + + return [{'asn': asn if asn is not None else C.DEFAULT_ASN, # Set "None" ASNs to default + 'name': asn_name_query(asn), + 'ipv4_origin_count': self.db['bgp'].count_documents( + {'origin_asn': asn, 'ip_version': 4, 'active': True}), + 'ipv6_origin_count': self.db['bgp'].count_documents( + {'origin_asn': asn, 'ip_version': 6, 'active': True}), + 'ipv4_nexthop_count': self.db['bgp'].count_documents( + {'nexthop_asn': asn, 'ip_version': 4, 'active': True}), + 'ipv6_nexthop_count': self.db['bgp'].count_documents( + {'nexthop_asn': asn, 'ip_version': 6, 'active': True}), + 'asn_count': len(self.db['bgp'].distinct('as_path.1', {'nexthop_asn': asn, 'active': True}))} + for asn in query_results] + + def avg_as_path_len(self, decimal_point_accuracy=2): + """Return the computed average *as_path* length of all prefixes in the + database. Using a python *set* to remove any AS prepending.""" + as_path_counter = 0 + all_prefixes = list(self.db['bgp'].find({'active': True})) + for prefix in all_prefixes: + try: + as_path_counter += len(set(prefix['as_path'])) # sets remove duplicate ASN prepending + except Exception: + pass + return round(as_path_counter / (len(all_prefixes) * 1.0), decimal_point_accuracy) + + def communities_count(self): + """Return a list of BGP communities and their count""" + return [{'community': community, + # 'count': self.db['bgp'].count_documents({'communities': {'$regex': str(community)}, 'active': True}), + 'count': self.db['bgp'].count_documents({'communities': str(community), 'active': True}), + 'name': None if C.BGP_COMMUNITY_MAP.get(community) is None else C.BGP_COMMUNITY_MAP.get(community)} + for community in self.db['bgp'].distinct('communities') if community is not None] + + def cidrs(self): + """ Return a list of IPv4 and IPv6 network mask counters.""" + ipv4_masks = [int(prefix['_id'].split('/', 1)[1]) + for prefix in self.db['bgp'].find({'ip_version': 4, 'active': True})] + ipv6_masks = [int(prefix['_id'].split('/', 1)[1]) + for prefix in self.db['bgp'].find({'ip_version': 6, 'active': True})] + # Use a *Counter* to count masks in the lists, then combine, sort on mask, and return results + return sorted( + [{'mask': mask, + 'count': count, + 'ip_version': 4} + for mask, count in list(Counter(ipv4_masks).items())] + + + [{'mask': mask, + 'count': count, + 'ip_version': 6} + for mask, count in list(Counter(ipv6_masks).items())], key=lambda x: x['mask']) + + def top_peers(self, count): + """Return a sorted list of top peer dictionaries ordered by prefix count. + Limit to *count*.""" + peers = {peer: self.db['bgp'].count_documents({'nexthop_asn': peer, 'active': True}) + for peer in self.db['bgp'].distinct('nexthop_asn')} + return [{'asn': asn[0], + 'count': asn[1], + 'name': asn_name_query(asn[0])} + for asn in self.take(count, sorted(peers.items(), key=lambda x: x[1], reverse=True))] + + def get_data(self, json=False): + data_dict = { + 'peer_count': self.peer_counter, + 'ipv6_table_size': self.ipv6_table_size, + 'ipv4_table_size': self.ipv4_table_size, + 'nexthop_ip_count': self.nexthop_ip_counter, + 'avg_as_path_length': self.avg_as_path_length, + 'top_n_peers': self.top_n_peers, + 'cidr_breakdown': self.cidr_breakdown, + 'communities': self.communities, + 'peers': self.peers, + 'customers': self.customers, + 'customer_count': self.customer_count, + 'customer_ipv4_prefixes': self.customer_ipv4_prefixes, + 'customer_ipv6_prefixes': self.customer_ipv6_prefixes, + 'timestamp': self.timestamp} + if json: + return jsonify(data_dict) + else: + return data_dict + + def update_stats(self): + self.peer_counter = self.peer_count() + self.ipv4_table_size = self.prefix_count(4) + self.ipv6_table_size = self.prefix_count(6) + self.nexthop_ip_counter = self.nexthop_ip_count() + self.timestamp = self.epoch_to_date(time.time()) + + def update_advanced_stats(self): + self.avg_as_path_length = self.avg_as_path_len() + self.top_n_peers = self.top_peers(5) + self.cidr_breakdown = self.cidrs() + # self.customers = self.get_list_of(customers=True) + self.communities = self.communities_count() + self.customers = self.get_list_of(customers=True) + self.peers = self.get_list_of(peers=True) + self.customer_count = len(self.customers) + self.customer_ipv4_prefixes = 0 + self.customer_ipv6_prefixes = 0 + for customer in self.customers: + self.customer_ipv4_prefixes += customer['ipv4_origin_count'] + self.customer_ipv6_prefixes += customer['ipv6_origin_count'] + self.timestamp = self.epoch_to_date(time.time()) diff --git a/flask/app/bgp.py b/flask/app/bgp.py new file mode 100644 index 0000000..8109182 --- /dev/null +++ b/flask/app/bgp.py @@ -0,0 +1,237 @@ +import threading + +from flask import Flask, jsonify, render_template + +import constants as C +from apscheduler.schedulers.background import BackgroundScheduler +from functions import (asn_name_query, get_ip_json, is_peer, is_transit, + reverse_dns_query, dns_query) +from Stats import Stats + +app = Flask(__name__) +app.config['JSON_SORT_KEYS'] = False +app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True + + +@app.route('/', methods=['GET']) +def bgp_index(): + data = myStats.get_data() + top_peers = data['top_n_peers'] + cidr_breakdown = data['cidr_breakdown'] + communities = data['communities'] + peers = data['peers'] + source_asn = C.DEFAULT_ASN + source_asn_name = asn_name_query(C.DEFAULT_ASN) + customer_bgp_community = C.CUSTOMER_BGP_COMMUNITY + transit_bgp_community = C.TRANSIT_BGP_COMMUNITY + peer_bgp_community = C.PEER_BGP_COMMUNITY + return render_template('bgp.html', **locals()) + + +@app.route('/bgp/api/v1.0/peers', methods=['GET']) +def get_peers(): + return jsonify(myStats.get_list_of(peers=True)) + + +@app.route('/bgp/api/v1.0/customers', methods=['GET']) +def get_customers(): + return jsonify(myStats.get_list_of(customers=True)) + + +@app.route('/bgp/api/v1.0/ip/', methods=['GET']) +def get_ip(ip): + return jsonify(get_ip_json(ip, include_history=False)) + + +@app.route('/bgp/api/v1.0/communities', methods=['GET']) +def get_communities(): + return jsonify(myStats.communities_count()) + + +@app.route('/bgp/api/v1.0/ip//history', methods=['GET']) +def get_history(ip): + return jsonify(get_ip_json(ip, include_history=True)) + + +@app.route('/bgp/api/v1.0/asn/', methods=['GET']) +def get_asn_prefixes(asn): + db = myStats.db + prefixes = [] + + if asn == C.DEFAULT_ASN: + routes = list(db['bgp'].find({'origin_asn': None, 'active': True})) + else: + routes = list(db['bgp'].find({'origin_asn': asn, 'active': True})) + + for prefix in routes: + prefixes.append({'prefix': prefix['_id'], + 'is_transit': is_transit(prefix), + 'origin_asn': prefix['origin_asn'], + 'name': asn_name_query(asn), + 'nexthop_ip': prefix['nexthop'], + 'nexthop_ip_dns': reverse_dns_query(prefix['nexthop']), + 'nexthop_asn': prefix['nexthop_asn'], + 'as_path': prefix['as_path'], + 'updated': prefix['age'] + }) + + return jsonify({'asn': asn, + 'name': asn_name_query(asn), + 'origin_prefix_count': len(routes), + 'is_peer': is_peer(asn), + 'origin_prefix_list': prefixes}) + + +@app.route('/bgp/api/v1.0/stats', methods=['GET']) +def get_stats(): + return myStats.get_data(json=True) + + +@app.route('/bgp/api/v1.0/asn//downstream', methods=['GET']) +def get_downstream_asns(asn): + db = myStats.db + asn_list = [] + large_query = 200 + downstream_asns = db['bgp'].distinct('as_path.1', {'nexthop_asn': asn, 'active': True}) + for downstream in downstream_asns: + if len(downstream_asns) > large_query: + dns_name = "(LARGE QUERY - DNS LOOKUP DISABLED)" + else: + dns_name = asn_name_query(downstream) + asn_list.append({'asn': downstream, 'name': dns_name}) + + sorted_asn_list = sorted(asn_list, key=lambda k: k['asn']) + + return jsonify({'asn': asn, + 'name': asn_name_query(asn), + 'downstream_asns_count': len(asn_list), + 'downstream_asns': sorted_asn_list}) + + +@app.route('/bgp/api/v1.0/asn//originated', methods=['GET']) +def get_originated_prefixes(asn): + db = myStats.db + originated = [] + prefixes = db['bgp'].find({'origin_asn': asn, 'active': True}) + for prefix in prefixes: + originated.append(prefix['_id']) + + return jsonify({'asn': asn, + 'name': asn_name_query(asn), + 'originated_prefix_count': len(originated), + 'originated_prefix_list': originated}) + + +@app.route('/bgp/api/v1.0/asn//originated/', methods=['GET']) +def get_originated_prefixes_version(asn, version): + db = myStats.db + originated = [] + v = 4 + if version.lower() == 'ipv6': + v = 6 + prefixes = db['bgp'].find({'origin_asn': asn, 'ip_version': v, 'active': True}) + for prefix in prefixes: + originated.append(prefix['_id']) + + return jsonify({'asn': asn, + 'name': asn_name_query(asn), + 'originated_prefix_count': len(originated), + 'originated_prefix_list': originated}) + + +@app.route('/bgp/api/v1.0/asn//nexthop', methods=['GET']) +def get_nexthop_prefixes(asn): + db = myStats.db + nexthop = [] + prefixes = db['bgp'].find({'nexthop_asn': asn, 'active': True}) + for prefix in prefixes: + nexthop.append(prefix['_id']) + + return jsonify({'asn': asn, + 'name': asn_name_query(asn), + 'nexthop_prefix_count': len(nexthop), + 'nexthop_prefix_list': nexthop}) + + +@app.route('/bgp/api/v1.0/asn//nexthop/', methods=['GET']) +def get_nexthop_prefixes_version(asn, version): + db = myStats.db + nexthop = [] + v = 4 + if version.lower() == 'ipv6': + v = 6 + prefixes = db['bgp'].find({'nexthop_asn': asn, 'ip_version': v, 'active': True}) + for prefix in prefixes: + nexthop.append(prefix['_id']) + + return jsonify({'asn': asn, + 'name': asn_name_query(asn), + 'nexthop_prefix_count': len(nexthop), + 'nexthop_prefix_list': nexthop}) + + +@app.route('/bgp/api/v1.0/asn//transit', methods=['GET']) +def get_transit_prefixes(asn): + db = myStats.db + all_asns = db['bgp'].find({'active': True}) + prefixes = [] + + for prefix in all_asns: + if prefix['as_path']: + if asn in prefix['as_path']: + prefixes.append(prefix['_id']) + else: + pass + else: + pass + + return jsonify({'asn': asn, + 'name': asn_name_query(asn), + 'transit_prefix_count': len(prefixes), + 'transit_prefix_list': prefixes}) + + +@app.route('/bgp/api/v1.0/domain/', methods=['GET']) +def get_domain(domain): + domain = domain.lower() + org = domain.split('.')[-2] + name_servers = dns_query(domain, 'NS') + soa = dns_query(domain, 'SOA') + local_ns = '' + if org in soa.lower(): + local_ns = soa.lower() + for ns in name_servers: + if org in ns.lower(): + local_ns = ns.lower() + if local_ns == '': + return jsonify({}) + else: + domain_ip = str(dns_query(local_ns)) + ip_data = get_ip_json(domain_ip) + asn = ip_data.get('origin_asn') + db = myStats.db + originated = [] + prefixes = db['bgp'].find({'origin_asn': asn, 'active': True}) + for prefix in prefixes: + originated.append(prefix['_id']) + + return jsonify({'domain': domain, + 'A Record': dns_query(domain), + 'SOA/NS Record': local_ns, + 'SOA/NS IP': domain_ip, + 'asn': asn, + 'name': asn_name_query(asn), + 'originated_prefix_count': len(originated), + 'originated_prefix_list': originated}) + + +sched = BackgroundScheduler() +myStats = Stats() +threading.Thread(target=myStats.update_stats).start() +threading.Thread(target=myStats.update_advanced_stats).start() +sched.add_job(myStats.update_stats, 'interval', seconds=60) +sched.add_job(myStats.update_advanced_stats, 'interval', seconds=300) +sched.start() + +if __name__ == '__main__': + app.run(debug=True) diff --git a/flask/app/constants.py b/flask/app/constants.py new file mode 100644 index 0000000..38d9b15 --- /dev/null +++ b/flask/app/constants.py @@ -0,0 +1,31 @@ +# DEFAULTS - UPDATE ACCORDINGLY +DEFAULT_ASN = 400848 +CUSTOMER_BGP_COMMUNITY = '3701:370' # Prefixes learned from directly connected customers +TRANSIT_BGP_COMMUNITY = '3701:380' # Prefixes learned from *paid* transit providers +PEER_BGP_COMMUNITY = '3701:39' # Community Prefix (starts with) for Prefixes learned from bilateral peers and exchanges +BGP_COMMUNITY_MAP = { + '3701:111': 'Level3-Prepend-1', + '3701:112': 'Level3-Prepend-2', + '3701:113': 'Level3-SEAT-Depref', + '3701:114': 'Level3-WSAC-Depref', + '3701:121': 'Level3-WSAC-Prepend-1', + '3701:122': 'Level3-WSAC-Prepend-2', + '3701:370': 'Customers', + '3701:371': 'Customers-NO-I2-RE', + '3701:372': 'Customers-NO-I2-CP', + '3701:380': 'Transit', + '3701:381': 'Level3-SEAT', + '3701:382': 'Level3-WSAC', + '3701:390': 'OIX', + '3701:391': 'I2-RE', + '3701:392': 'NWAX', + '3701:393': 'PNWGP', + '3701:394': 'I2-CPS', + '3701:395': 'SeattleIX', + '3701:500': 'PT-ODE-USERS', + '3701:501': 'PT-ODE-PROVIDERS', + '3701:666': 'BH-LOCAL', + '64496:0': 'Cymru-UTRS', + '65333:888': 'Cymru-BOGONs', + '65535:65281': 'No-Export', +} diff --git a/flask/app/functions.py b/flask/app/functions.py new file mode 100644 index 0000000..78ae383 --- /dev/null +++ b/flask/app/functions.py @@ -0,0 +1,145 @@ +import ipaddress +from functools import cache + +import dns.resolver +from pymongo.database import Database + +import constants as C +from flask import jsonify, request +from pymongo import MongoClient + + +@cache +def db_connect() -> Database: + """Return a connection to the Mongo Database.""" + client = MongoClient(host='mongodb') + return client["bgp"] + + +def find_network(ip, netmask): + """Given an IPv4 or IPv6 address, recursively search for and return the most + specific prefix in the MongoDB collection that is active. + """ + try: + db = db_connect() + network = str(ipaddress.ip_network(ipaddress.ip_address(ip)).supernet(new_prefix=netmask)) + result = db['bgp'].find_one({'_id': network, 'active': True}) + if result is not None: + return result + elif netmask == 0: + return None + else: + return find_network(ip, netmask - 1) + except Exception: + return None + + +def is_peer(asn): + """Is *asn* in the list of directy connected ASNs.""" + db = db_connect() + if asn in db['bgp'].distinct('nexthop_asn'): + return True + else: + return False + + +def is_transit(prefix, transit_bgp_community=C.TRANSIT_BGP_COMMUNITY): + """Is the *prefix* counted as transit?""" + if C.TRANSIT_BGP_COMMUNITY in prefix['communities']: + return True + else: + return False + + +def reverse_dns_query(ip): + """Given an *ip*, return the reverse dns.""" + try: + addr = dns.reversename.from_address(str(ip)) + resolver = dns.resolver.Resolver() + return str(resolver.resolve(addr, 'PTR')[0])[:-1] + except Exception: + return '(DNS Error)' + + +def dns_query(name, type='A'): + """Given a *name*, return the ip dns.""" + try: + # addr = dns.reversename.from_address(str(ip)) + resolver = dns.resolver.Resolver() + answers = resolver.resolve(str(name), type) + if type == 'A': + return str(answers[0]) + elif type == 'NS': + domains = [] + for record in answers: + domains.append(str(record.target)) + return domains + elif type == 'SOA': + return str(answers[0]).split()[0] + except Exception: + return '(DNS Error)' + + +def asn_name_query(asn): + """Given an *asn*, return the name.""" + if asn is None: + asn = C.DEFAULT_ASN + if 64496 <= asn <= 64511: + return ('RFC5398 - Private Use ASN') + if 64512 <= asn <= 65535 or 4200000000 <= asn <= 4294967295: + return ('RFC6996 - Private Use ASN') + try: + query = 'as{number}.asn.cymru.com'.format(number=str(asn)) + resolver = dns.resolver.Resolver() + answers = resolver.resolve(query, 'TXT') + for rdata in answers: + return (str(rdata).split('|')[-1].split(',', 2)[0].strip()) + except Exception: + return '(DNS Error)' + + +def get_ip_json(ip, include_history=True): + if '/' in ip: + ip = ip.lstrip().rstrip().split('/')[0] + try: + if ipaddress.ip_address(ip).version == 4: + network = find_network(ip, netmask=32) + elif ipaddress.ip_address(ip).version == 6: + network = find_network(ip, netmask=128) + except Exception: + try: + ipadr = dns_query(ip).strip() + if ipaddress.ip_address(ipadr).version == 4: + network = find_network(ipadr, netmask=32) + elif ipaddress.ip_address(ipadr).version == 6: + network = find_network(ipadr, netmask=128) + except Exception as e: + return jsonify(str(e)) + if network: + if include_history: + history = network['history'] + else: + history = request.base_url + '/history' + return {'prefix': network['_id'], + 'ip_version': network['ip_version'], + 'is_transit': is_transit(network), + 'origin_asn': network['origin_asn'], + 'name': asn_name_query(network['origin_asn']), + 'nexthop': network['nexthop'], + 'nexthop_ip_dns': reverse_dns_query(network['nexthop']), + 'nexthop_asn': network['nexthop_asn'], + 'as_path': network['as_path'], + 'med': network['med'], + 'local_pref': network['local_pref'], + 'communities': network['communities'], + 'route_origin': network['route_origin'], + 'atomic_aggregate': network['atomic_aggregate'], + 'aggregator_as': network['aggregator_as'], + 'aggregator_address': network['aggregator_address'], + 'originator_id': network['originator_id'], + 'originator_id_dns': reverse_dns_query(network['originator_id']), + 'cluster_list': network['cluster_list'], + 'age': network['age'], + 'history': history} + else: + return {} diff --git a/flask/app/requirements.txt b/flask/app/requirements.txt new file mode 100644 index 0000000..b808cc1 --- /dev/null +++ b/flask/app/requirements.txt @@ -0,0 +1,9 @@ +uwsgi >= 2.0.26 +flask >= 3.0.3 +requests >= 2.32.3 +apscheduler >= 3.10.4 +pytz >= 2024.1 + +pymongo >= 4.8.0 +dnspython >= 2.6.1 +ipaddress >= 1.0.23 diff --git a/flask/app/static/css/custom.css b/flask/app/static/css/custom.css new file mode 100644 index 0000000..bde6269 --- /dev/null +++ b/flask/app/static/css/custom.css @@ -0,0 +1,3989 @@ +.jqstooltip { + width: auto !important; + height: auto !important; +} +.daterangepicker .ranges li { + color: #73879C; } + .daterangepicker .ranges li.active, .daterangepicker .ranges li:hover { + background: #536A7F; + border: 1px solid #536A7F; + color: #fff; } +.daterangepicker .input-mini { + background-color: #eee; + border: 1px solid #ccc; + box-shadow: none !important; } + .daterangepicker .input-mini.active { + border: 1px solid #ccc; } +.daterangepicker select.monthselect, .daterangepicker select.yearselect, .daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect { + font-size: 12px; + padding: 1px; + height: auto; + margin: 0; + cursor: default; + height: 30px; + border: 1px solid #ADB2B5; + line-height: 30px; + border-radius: 0px !important; } +.daterangepicker select.monthselect { + margin-right: 2%; } +.daterangepicker td.in-range { + background: #E4E7EA; + color: #73879C; } +.daterangepicker td.active, .daterangepicker td.active:hover { + background-color: #536A7F; + color: #fff; } +.daterangepicker th.available:hover { + background: #eee; + color: #34495E; } +.daterangepicker:before, .daterangepicker:after { + content: none; } +.daterangepicker .calendar.single { + margin: 0 0 4px 0; } + .daterangepicker .calendar.single .calendar-table { + width: 224px; + padding: 0 0 4px 0 !important; } + .daterangepicker .calendar.single .calendar-table thead tr:first-child th { + padding: 8px 5px; } + .daterangepicker .calendar.single .calendar-table thead th { + border-radius: 0; } +.daterangepicker.picker_1 { + color: #fff; + background: #34495E; } + .daterangepicker.picker_1 .calendar-table { + background: #34495E; } + .daterangepicker.picker_1 .calendar-table thead tr { + background: #213345; } + .daterangepicker.picker_1 .calendar-table thead tr:first-child { + background: #1ABB9C; } + .daterangepicker.picker_1 .calendar-table td.off { + background: #34495E; + color: #999; } + .daterangepicker.picker_1 .calendar-table td.available:hover { + color: #34495E; } +.daterangepicker.picker_2 .calendar-table thead tr { + color: #1ABB9C; } +.daterangepicker.picker_2 .calendar-table thead tr:first-child { + color: #73879C; } +.daterangepicker.picker_3 .calendar-table thead tr:first-child { + color: #fff; + background: #1ABB9C; } +.daterangepicker.picker_4 .calendar-table thead tr:first-child { + color: #fff; + background: #34495E; } +.daterangepicker.picker_4 .calendar-table td, .daterangepicker.picker_4 .calendar-table td.off { + background: #ECF0F1; + border: 1px solid #fff; + border-radius: 0; } +.daterangepicker.picker_4 .calendar-table td.active { + background: #34495E; } + +.calendar-exibit .show-calendar { + float: none; + display: block; + position: relative; + background-color: #fff; + border: 1px solid #ccc; + margin-bottom: 20px; + border: 1px solid rgba(0, 0, 0, 0.15); + overflow: hidden; } + .calendar-exibit .show-calendar .calendar { + margin: 0 0 4px 0; } + .calendar-exibit .show-calendar.picker_1 { + background: #34495E; } +.calendar-exibit .calendar-table { + padding: 0 0 4px 0; } + +@charset "UTF-8"; +.left_col { + background: #2A3F54; } + +.nav-sm .container.body .col-md-3.left_col { + min-height: 100%; + width: 70px; + padding: 0; + z-index: 9999; + position: absolute; } + +.nav-sm .container.body .col-md-3.left_col.menu_fixed { + position: fixed; + height: 100%; } + +.nav-sm .container.body .col-md-3.left_col .mCSB_container, +.nav-sm .container.body .col-md-3.left_col .mCustomScrollBox { + overflow: visible; } + +.nav-sm .hidden-small { + visibility: hidden; } + +.nav-sm .container.body .right_col { + padding: 10px 20px; + margin-left: 70px; + z-index: 2; } + +.nav-sm .navbar.nav_title { + width: 70px; } + +.nav-sm .navbar.nav_title a span { + display: none; } + +.nav-sm .navbar.nav_title a i { + font-size: 27px; + margin: 13px 0 0 3px; } + +.site_title i { + border: 1px solid #EAEAEA; + padding: 5px 6px; + border-radius: 50%; } + +.nav-sm .main_container .top_nav { + display: block; + margin-left: 70px; + z-index: 2; } + +.nav-sm .nav.side-menu li a { + text-align: center !important; + font-weight: 400; + font-size: 10px; + padding: 10px 5px; } + +.nav-sm .nav.child_menu li.active, +.nav-sm .nav.side-menu li.active-sm { + border-right: 5px solid #1ABB9C; } + +.nav-sm ul.nav.child_menu ul, +.nav-sm .nav.side-menu li.active-sm ul ul { + position: static; + width: 200px; + background: none; } + +.nav-sm > .nav.side-menu > li.active-sm > a { + color: #1ABB9C !important; } + +.nav-sm .nav.side-menu li a i.toggle-up { + display: none !important; } + +.nav-sm .nav.side-menu li a i { + font-size: 25px !important; + text-align: center; + width: 100% !important; + margin-bottom: 5px; } + +.nav-sm ul.nav.child_menu { + left: 100%; + position: absolute; + top: 0; + width: 210px; + z-index: 4000; + background: #3E5367; + display: none; } + +.nav-sm ul.nav.child_menu li { + padding: 0 10px; } + +.nav-sm ul.nav.child_menu li a { + text-align: left !important; } + +.nav-sm .profile { + display: none; } + +.menu_section { + margin-bottom: 35px; } + +.menu_section h3 { + padding-left: 23px; + color: #fff; + text-transform: uppercase; + letter-spacing: .5px; + font-weight: bold; + font-size: 11px; + margin-bottom: 0; + margin-top: 0; + text-shadow: 1px 1px #000; } + +.menu_section > ul { + margin-top: 10px; } + +.profile_pic { + width: 35%; + float: left; } + +.img-circle.profile_img { + width: 70%; + background: #fff; + margin-left: 15%; + z-index: 1000; + position: inherit; + margin-top: 20px; + border: 1px solid rgba(52, 73, 94, 0.44); + padding: 4px; } + +.profile_info { + padding: 25px 10px 10px; + width: 65%; + float: left; } + +.profile_info span { + font-size: 13px; + line-height: 30px; + color: #BAB8B8; } + +.profile_info h2 { + font-size: 14px; + color: #ECF0F1; + margin: 0; + font-weight: 300; } + +.profile.img_2 { + text-align: center; } + +.profile.img_2 .profile_pic { + width: 100%; } + +.profile.img_2 .profile_pic .img-circle.profile_img { + width: 50%; + margin: 10px 0 0; } + +.profile.img_2 .profile_info { + padding: 15px 10px 0; + width: 100%; + margin-bottom: 10px; + float: left; } + +.main_menu span.fa { + float: right; + text-align: center; + margin-top: 5px; + font-size: 10px; + min-width: inherit; + color: #C4CFDA; } + +.active a span.fa { + text-align: right !important; + margin-right: 4px; } + +.nav-sm .menu_section { + margin: 0; } + +.nav-sm span.fa, +.nav-sm .menu_section h3 { + display: none; } + +.nav-sm li li span.fa { + display: inline-block; } + +.nav_menu { + float: left; + background: #EDEDED; + border-bottom: 1px solid #D9DEE4; + margin-bottom: 10px; + width: 100%; + position: relative; } + +@media (min-width: 480px) { + .nav_menu { + position: static; } } +.nav-md .container.body .col-md-3.left_col { + min-height: 100%; + width: 230px; + padding: 0; + position: absolute; + display: -ms-flexbox; + display: flex; + z-index: 1; } + +.nav-md .container.body .col-md-3.left_col.menu_fixed { + height: 100%; + position: fixed; } + +body .container.body .right_col { + background: #F7F7F7; } + +.nav-md .container.body .right_col { + padding: 10px 20px 0; + margin-left: 0px; } + +.nav_title { + width: 230px; + float: left; + background: #2A3F54; + border-radius: 0; + height: 57px; } + +@media (max-width: 991px) { + .nav-md .container.body .right_col, .nav-md .container.body .top_nav { + width: 100%; + margin: 0; } + + .nav-md .container.body .col-md-3.left_col { + display: none; } + + .nav-md .container.body .right_col { + width: 100%; + padding-right: 0; } + + .right_col { + padding: 10px !important; } } +@media (max-width: 1200px) { + .x_title h2 { + width: 62%; + font-size: 17px; } + + .tile, .graph { + zoom: 85%; + height: inherit; } } +@media (max-width: 1270px) and (min-width: 192px) { + .x_title h2 small { + display: none; } } +.left_col .mCSB_scrollTools { + width: 6px; } + +.left_col .mCSB_dragger { + max-height: 400px !important; } + +/** ------------------------------------------ **/ +.blue { + color: #3498DB; } + +.purple { + color: #9B59B6; } + +.green { + color: #1ABB9C; } + +.aero { + color: #9CC2CB; } + +.red { + color: #E74C3C; } + +.dark { + color: #34495E; } + +.border-blue { + border-color: #3498DB !important; } + +.border-purple { + border-color: #9B59B6 !important; } + +.border-green { + border-color: #1ABB9C !important; } + +.border-aero { + border-color: #9CC2CB !important; } + +.border-red { + border-color: #E74C3C !important; } + +.border-dark { + border-color: #34495E !important; } + +.bg-white { + background: #fff !important; + border: 1px solid #fff !important; + color: #73879C; } + +.bg-green { + background: #1ABB9C !important; + border: 1px solid #1ABB9C !important; + color: #fff; } + +.bg-red { + background: #E74C3C !important; + border: 1px solid #E74C3C !important; + color: #fff; } + +.bg-blue { + background: #3498DB !important; + border: 1px solid #3498DB !important; + color: #fff; } + +.bg-orange { + background: #F39C12 !important; + border: 1px solid #F39C12 !important; + color: #fff; } + +.bg-purple { + background: #9B59B6 !important; + border: 1px solid #9B59B6 !important; + color: #fff; } + +.bg-blue-sky { + background: #50C1CF !important; + border: 1px solid #50C1CF !important; + color: #fff; } + +.container { + width: 100%; + padding: 0; } + +.navbar-nav > li > a, .navbar-brand, .navbar-nav > li > a { + color: #fff !important; } + +.top_nav .nav > li > a:focus, .top_nav .nav > li > a:hover, .top_nav .nav .open > a, .top_nav .nav .open > a:focus, .top_nav .nav .open > a:hover { + background: #D9DEE4; } + +body { + color: #73879C; + background: #2A3F54; + font-family: "Helvetica Neue", Roboto, Arial, "Droid Sans", sans-serif; + font-size: 13px; + font-weight: 400; + line-height: 1.471; } + +.main_container .top_nav { + display: block; + margin-left: 0px; } + +.no-padding { + padding: 0 !important; } + +.page-title { + width: 100%; + height: 65px; + padding: 10px 0; } + +.page-title .title_left { + width: 45%; + float: left; + display: block; } + +.page-title .title_left h3 { + margin: 9px 0; } + +.page-title .title_right { + width: 55%; + float: left; + display: block; } + +.page-title .title_right .pull-right { + margin: 10px 0; } + +.fixed_height_320 { + height: 320px; } + +.fixed_height_390 { + height: 390px; } + +.fixed_height_200 { + height: 200px; } + +.overflow_hidden { + overflow: hidden; } + +.progress-bar-dark { + background-color: #34495E !important; } + +.progress-bar-gray { + background-color: #BDC3C7 !important; } + +table.no-margin .progress { + margin-bottom: 0; } + +.main_content { + padding: 10px 20px; } + +.col-md-55 { + width: 50%; + margin-bottom: 10px; } + +@media (min-width: 768px) { + .col-md-55 { + width: 20%; } } +@media (min-width: 992px) { + .col-md-55 { + width: 20%; } } +@media (min-width: 1200px) { + .col-md-55 { + width: 20%; } } +@media (min-width: 192px) and (max-width: 1270px) { + table.tile_info span.right { + margin-right: 7px; + float: left; } } +.center-margin { + margin: 0 auto; + float: none !important; } + +.col-md-55, .col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + float: left; + padding-right: 10px; + padding-left: 10px; } + +.row { + margin-right: -10px; + margin-left: -10px; } + +.grid_slider .col-md-6 { + padding: 0 40px; } + +h1, .h1, h2, .h2, h3, .h3 { + margin-top: 10px; + margin-bottom: 10px; } + +a { + color: #5A738E; + text-decoration: none; } + +a, a:visited, a:focus, a:active, :visited, :focus, :active, .btn:focus, .btn:active:focus, .btn.active:focus, .btn.focus, .btn:active.focus, .btn.active.focus { + outline: 0; } + +a:hover, a:focus { + text-decoration: none; } + +.navbar { + margin-bottom: 0; } + +.navbar-header { + background: #34495E; } + +.navbar-right { + margin-right: 0; } + +.top_nav .navbar-right { + margin: 0; + width: 70%; + float: right; } + +.top_nav .nav-menu .navbar-left { + color: #5A738E; + margin: 10000; + width: 70%; + float: right; } + +.top_nav .navbar-right li { + display: inline-block; + float: right; + position: static; } + +@media (min-width: 480px) { + .top_nav .navbar-right li { + position: relative; } } +.top_nav .dropdown-menu li { + width: 100%; } + +.top_nav .dropdown-menu li a { + width: 100%; + padding: 12px 20px; } + +.top_nav li a i { + font-size: 15px; } + +.navbar-static-top { + position: fixed; + top: 0; + width: 100%; } + +.sidebar-header { + border-bottom: 0; + margin-top: 46px; } + +.sidebar-header:first-of-type { + margin-top: 0; } + +.nav.side-menu > li { + position: relative; + display: block; + cursor: pointer; } + +.nav.side-menu > li > a { + margin-bottom: 6px; } + +.nav.side-menu > li > a:hover { + color: #F2F5F7 !important; } + +.nav.side-menu > li > a:hover, .nav > li > a:focus { + text-decoration: none; + background: transparent; } + +.nav.child_menu { + display: none; } + +.nav.child_menu li:hover, +.nav.child_menu li.active { + background-color: rgba(255, 255, 255, 0.06); } + +.nav.child_menu li { + padding-left: 36px; } + +.nav-md ul.nav.child_menu li:before { + background: #425668; + bottom: auto; + content: ""; + height: 8px; + left: 23px; + margin-top: 15px; + position: absolute; + right: auto; + width: 8px; + z-index: 1; + border-radius: 50%; } + +.nav-md ul.nav.child_menu li:after { + border-left: 1px solid #425668; + bottom: 0; + content: ""; + left: 27px; + position: absolute; + top: 0; } + +.nav.side-menu > li > a, .nav.child_menu > li > a { + color: #E7E7E7; + font-weight: 500; } + +.nav.child_menu li li:hover, +.nav.child_menu li li.active { + background: none; } + +.nav.child_menu li li a:hover, +.nav.child_menu li li a.active { + color: #fff; } + +.nav > li > a { + position: relative; + display: block; + padding: 13px 15px 12px; } + +.nav.side-menu > li.current-page, .nav.side-menu > li.active { + border-right: 5px solid #1ABB9C; } + +.nav li.current-page { + background: rgba(255, 255, 255, 0.05); } + +.nav li li li.current-page { + background: none; } + +.nav li li.current-page a { + color: #fff; } + +.nav.side-menu > li.active > a { + text-shadow: rgba(0, 0, 0, 0.25) 0 -1px 0; + background: linear-gradient(#334556, #2C4257), #2A3F54; + box-shadow: rgba(0, 0, 0, 0.25) 0 1px 0, inset rgba(255, 255, 255, 0.16) 0 1px 0; } + +.navbar-brand, .navbar-nav > li > a { + font-weight: 500; + color: #ECF0F1 !important; + margin-left: 0 !important; + line-height: 32px; } + +.site_title { + text-overflow: ellipsis; + overflow: hidden; + font-weight: 400; + font-size: 22px; + width: 100%; + color: #ECF0F1 !important; + margin-left: 0 !important; + line-height: 59px; + display: block; + height: 55px; + margin: 0; + padding-left: 10px; } + +.site_title:hover, .site_title:focus { + text-decoration: none; } + +.nav.navbar-nav > li > a { + color: #515356 !important; } + +.nav.top_menu > li > a { + position: relative; + display: block; + padding: 10px 15px; + color: #34495E !important; } + +.nav > li > a:hover, .nav > li > a:focus { + background-color: transparent; } + +.top_search { + padding: 0; } + +.top_search .form-control { + border-right: 0; + box-shadow: inset 0 1px 0px rgba(0, 0, 0, 0.075); + border-radius: 25px 0px 0px 25px; + padding-left: 20px; + border: 1px solid rgba(221, 226, 232, 0.49); } + +.top_search .form-control:focus { + border: 1px solid rgba(221, 226, 232, 0.49); + border-right: 0; } + +.top_search .input-group-btn button { + border-radius: 0px 25px 25px 0px; + border: 1px solid rgba(221, 226, 232, 0.49); + border-left: 0; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + color: #93A2B2; + margin-bottom: 0 !important; } + +.toggle { + float: left; + margin: 0; + padding-top: 16px; + width: 70px; } + +.toggle a { + padding: 15px 15px 0; + margin: 0; + cursor: pointer; } + +.toggle a i { + font-size: 26px; } + +.nav.child_menu > li > a { + color: rgba(255, 255, 255, 0.75); + font-size: 12px; + padding: 9px; } + +.panel_toolbox { + float: right; + min-width: 70px; } + +.panel_toolbox > li { + float: left; + cursor: pointer; } + +.panel_toolbox > li > a { + padding: 5px; + color: #C5C7CB; + font-size: 14px; } + +.panel_toolbox > li > a:hover { + background: #F5F7FA; } + +.line_30 { + line-height: 30px; } + +.main_menu_side { + padding: 0; } + +.bs-docs-sidebar .nav > li > a { + display: block; + padding: 4px 6px; } + +footer { + background: #fff; + padding: 15px 20px; + display: block; } + +.nav-sm footer { + margin-left: 70px; } + +.footer_fixed footer { + position: fixed; + left: 0px; + bottom: 0px; + width: 100%; } + +@media (min-width: 768px) { + .footer_fixed footer { + margin-left: 0; } } +@media (min-width: 768px) { + .footer_fixed .nav-sm footer { + margin-left: 0; } } +.tile-stats.sparkline { + padding: 10px; + text-align: center; } + +.jqstooltip { + background: #34495E !important; + width: 30px !important; + height: 22px !important; + text-decoration: none; } + +.tooltip { + display: block !important; } + +.tiles { + border-top: 1px solid #ccc; + margin-top: 15px; + padding-top: 5px; + margin-bottom: 0; } + +.tile { + overflow: hidden; } + +.top_tiles { + margin-bottom: 0; } + +.top_tiles .tile h2 { + font-size: 30px; + line-height: 30px; + margin: 3px 0 7px; + font-weight: bold; } + +article.media { + width: 100%; } + +/* ********* custom accordion **************************** */ +*, *:before, *:after { + box-sizing: border-box; } + +#integration-list { + width: 100%; + margin: 0 auto; + display: table; } + +#integration-list ul { + padding: 0; + margin: 20px 0; + color: #555; } + +#integration-list ul > li { + list-style: none; + border-top: 1px solid #ddd; + display: block; + padding: 15px; + overflow: hidden; } + +#integration-list ul:last-child { + border-bottom: 1px solid #ddd; } + +#integration-list ul > li:hover { + background: #efefef; } + +.expand { + display: block; + text-decoration: none; + color: #555; + cursor: pointer; } + +.expand h2 { + width: 85%; + float: left; } + +h2 { + font-size: 18px; + font-weight: 400; } + +#left, #right { + display: table; } + +#sup { + display: table-cell; + vertical-align: middle; + width: 80%; } + +.detail a { + text-decoration: none; + color: #C0392B; + border: 1px solid #C0392B; + padding: 6px 10px 5px; + font-size: 13px; + margin-right: 7px; } + +.detail { + margin: 10px 0 10px 0px; + display: none; + line-height: 22px; + height: 150px; } + +.detail span { + margin: 0; } + +.right-arrow { + width: 10px; + float: right; + font-weight: bold; + font-size: 20px; } + +.accordion .panel { + margin-bottom: 5px; + border-radius: 0; + border-bottom: 1px solid #efefef; } + +.accordion .panel-heading { + background: #F2F5F7; + padding: 13px; + width: 100%; + display: block; } + +.accordion .panel:hover { + background: #F2F5F7; } + +.x_panel { + position: relative; + width: 100%; + margin-bottom: 10px; + padding: 10px 17px; + display: inline-block; + background: #fff; + border: 1px solid #E6E9ED; + -webkit-column-break-inside: avoid; + -moz-column-break-inside: avoid; + column-break-inside: avoid; + opacity: 1; + transition: all .2s ease; } + +.x_title { + border-bottom: 2px solid #E6E9ED; + padding: 1px 5px 6px; + margin-bottom: 10px; } + +.x_title .filter { + width: 40%; + float: right; } + +.x_title h2 { + margin: 5px 0 6px; + float: left; + display: block; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } + +.x_title h2 small { + margin-left: 10px; } + +.x_title span { + color: #BDBDBD; } + +.x_content { + padding: 0 5px 6px; + position: relative; + width: 100%; + float: left; + clear: both; + margin-top: 5px; } + +.x_content h4 { + font-size: 16px; + font-weight: 500; } + +legend { + padding-bottom: 7px; } + +.demo-placeholder { + height: 280px; } + +/** Contacts **/ +.profile_details:nth-child(3n) { + clear: both; } + +.profile_details .profile_view { + display: inline-block; + padding: 10px 0 0; + background: #fff; } + +.profile_details .profile_view .divider { + border-top: 1px solid #e5e5e5; + padding-top: 5px; + margin-top: 5px; } + +.profile_details .profile_view .ratings { + margin-bottom: 0; } + +.profile_details .profile_view .bottom { + background: #F2F5F7; + padding: 9px 0; + border-top: 1px solid #E6E9ED; } + +.profile_details .profile_view .left { + margin-top: 20px; } + +.profile_details .profile_view .left p { + margin-bottom: 3px; } + +.profile_details .profile_view .right { + margin-top: 0px; + padding: 10px; } + +.profile_details .profile_view .img-circle { + border: 1px solid #E6E9ED; + padding: 2px; } + +.profile_details .profile_view h2 { + margin: 5px 0; } + +.profile_details .profile_view .ratings { + text-align: left; + font-size: 16px; } + +.profile_details .profile_view .brief { + margin: 0; + font-weight: 300; } + +.profile_details .profile_left { + background: white; } + +.pagination.pagination-split li { + display: inline-block; + margin-right: 3px; } + +.pagination.pagination-split li a { + border-radius: 4px; + color: #768399; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; } + +/** Contacts **/ +/* ********* /custom accordion **************************** */ +/* ********* dashboard widget **************************** */ +table.tile h3, table.tile h4, table.tile span { + font-weight: bold; + vertical-align: middle !important; } + +table.tile th, table.tile td { + text-align: center; } + +table.tile th { + border-bottom: 1px solid #E6ECEE; } + +table.tile td { + padding: 5px 0; } + +table.tile td ul { + text-align: left; + padding-left: 0; } + +table.tile td ul li { + list-style: none; + width: 100%; } + +table.tile td ul li a { + width: 100%; } + +table.tile td ul li a big { + right: 0; + float: right; + margin-right: 13px; } + +table.tile_info { + width: 100%; } + +table.tile_info td { + text-align: left; + padding: 1px; + font-size: 15px; } + +table.tile_info td p { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin: 0; + line-height: 28px; } + +table.tile_info td i { + margin-right: 8px; + font-size: 17px; + float: left; + width: 18px; + line-height: 28px; } + +table.tile_info td:first-child { + width: 83%; } + +td span { + line-height: 28px; } + +.sidebar-widget { + overflow: hidden; } + +.error-number { + font-size: 90px; + line-height: 90px; + margin: 20px 0; } + +.col-middle { + margin-top: 5%; } + +.mid_center { + width: 370px; + margin: 0 auto; + text-align: center; + padding: 10px 20px; } + +h3.degrees { + font-size: 22px; + font-weight: 400; + text-align: center; } + +.degrees:after { + content: "o"; + position: relative; + top: -12px; + font-size: 13px; + font-weight: 300; } + +.daily-weather .day { + font-size: 14px; + border-top: 2px solid rgba(115, 135, 156, 0.36); + text-align: center; + border-bottom: 2px solid rgba(115, 135, 156, 0.36); + padding: 5px 0; } + +.weather-days .col-sm-2 { + overflow: hidden; + width: 16.66666667%; } + +.weather .row { + margin-bottom: 0; } + +/* ********* tables styling ******************************* */ +.bulk-actions { + display: none; } + +table.countries_list { + width: 100%; } + +table.countries_list td { + padding: 0 10px; + line-height: 30px; + border-top: 1px solid #eeeeee; } + +.dataTables_paginate a { + padding: 6px 9px !important; + background: #ddd !important; + border-color: #ddd !important; } + +.paging_full_numbers a.paginate_active { + background-color: rgba(38, 185, 154, 0.59) !important; + border-color: rgba(38, 185, 154, 0.59) !important; } + +button.DTTT_button, div.DTTT_button, a.DTTT_button { + border: 1px solid #E7E7E7 !important; + background: #E7E7E7 !important; + box-shadow: none !important; } + +table.jambo_table { + border: 1px solid rgba(221, 221, 221, 0.78); } + +table.jambo_table thead { + background: rgba(52, 73, 94, 0.94); + color: #ECF0F1; } + +table.jambo_table tbody tr:hover td { + background: rgba(38, 185, 154, 0.07); + border-top: 1px solid rgba(38, 185, 154, 0.11); + border-bottom: 1px solid rgba(38, 185, 154, 0.11); } + +table.jambo_table tbody tr.selected { + background: rgba(38, 185, 154, 0.16); } + +table.jambo_table tbody tr.selected td { + border-top: 1px solid rgba(38, 185, 154, 0.4); + border-bottom: 1px solid rgba(38, 185, 154, 0.4); } + +.dataTables_paginate a { + background: #ff0000; } + +.dataTables_wrapper { + position: relative; + clear: both; + zoom: 1; } + +.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 250px; + height: 30px; + margin-left: -125px; + margin-top: -15px; + padding: 14px 0 2px 0; + border: 1px solid #ddd; + text-align: center; + color: #999; + font-size: 14px; + background-color: white; } + +.dataTables_length { + width: 40%; + float: left; } + +.dataTables_filter { + width: 50%; + float: right; + text-align: right; } + +.dataTables_info { + width: 60%; + float: left; } + +.dataTables_paginate { + float: right; + text-align: right; } + +table.dataTable th.focus, +table.dataTable td.focus { + outline: 2px solid #1ABB9C !important; + outline-offset: -1px; } + +table.display { + margin: 0 auto; + clear: both; + width: 100%; } + +table.display thead th { + padding: 8px 18px 8px 10px; + border-bottom: 1px solid black; + font-weight: bold; + cursor: pointer; } + +table.display tfoot th { + padding: 3px 18px 3px 10px; + border-top: 1px solid black; + font-weight: bold; } + +table.display tr.heading2 td { + border-bottom: 1px solid #aaa; } + +table.display td { + padding: 3px 10px; } + +table.display td.center { + text-align: center; } + +table.display thead th:active, table.display thead td:active { + outline: none; } + +.dataTables_scroll { + clear: both; } + +.dataTables_scrollBody { + *margin-top: -1px; + -webkit-overflow-scrolling: touch; } + +.top .dataTables_info { + float: none; } + +.clear { + clear: both; } + +.dataTables_empty { + text-align: center; } + +tfoot input { + margin: 0.5em 0; + width: 100%; + color: #444; } + +tfoot input.search_init { + color: #999; } + +td.group { + background-color: #d1cfd0; + border-bottom: 2px solid #A19B9E; + border-top: 2px solid #A19B9E; } + +td.details { + background-color: #d1cfd0; + border: 2px solid #A19B9E; } + +.example_alt_pagination div.dataTables_info { + width: 40%; } + +.paging_full_numbers { + width: 400px; + height: 22px; + line-height: 22px; } + +.paging_full_numbers a:active { + outline: none; } + +.paging_full_numbers a:hover { + text-decoration: none; } + +.paging_full_numbers a.paginate_button, .paging_full_numbers a.paginate_active { + border: 1px solid #aaa; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + padding: 2px 5px; + margin: 0 3px; + cursor: pointer; } + +.paging_full_numbers a.paginate_button { + background-color: #ddd; } + +.paging_full_numbers a.paginate_button:hover { + background-color: #ccc; + text-decoration: none !important; } + +.paging_full_numbers a.paginate_active { + background-color: #99B3FF; } + +table.display tr.even.row_selected td { + background-color: #B0BED9; } + +table.display tr.odd.row_selected td { + background-color: #9FAFD1; } + +div.box { + height: 100px; + padding: 10px; + overflow: auto; + border: 1px solid #8080FF; + background-color: #E5E5FF; } + +/* ********* /tables styling ****************************** */ +/* ********* /dashboard widget **************************** */ +/* ********* widgets *************************************** */ +ul.msg_list li { + background: #f7f7f7; + padding: 5px; + display: -ms-flexbox; + display: flex; + margin: 6px 6px 0; + width: 96% !important; } + +ul.msg_list li:last-child { + margin-bottom: 6px; + padding: 10px; } + +ul.msg_list li a { + padding: 3px 5px !important; } + +ul.msg_list li a .image img { + border-radius: 2px 2px 2px 2px; + -webkit-border-radius: 2px 2px 2px 2px; + float: left; + margin-right: 10px; + width: 11%; } + +ul.msg_list li a .time { + font-size: 11px; + font-style: italic; + font-weight: bold; + position: absolute; + right: 35px; } + +ul.msg_list li a .message { + display: block !important; + font-size: 11px; } + +.dropdown-menu.msg_list span { + white-space: normal; } + +.dropdown-menu { + border: medium none; + box-shadow: none; + display: none; + float: left; + font-size: 12px; + left: 0; + list-style: none outside none; + padding: 0; + position: absolute; + text-shadow: none; + top: 100%; + z-index: 9998; + border: 1px solid #D9DEE4; + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.dropdown-menu > li > a { + color: #5A738E; } + +.navbar-nav .open .dropdown-menu { + position: absolute; + background: #fff; + margin-top: 0; + border: 1px solid #D9DEE4; + -webkit-box-shadow: none; + right: 0; + left: auto; + width: 220px; } + +.navbar-nav .open .dropdown-menu.msg_list { + width: 300px; } + +.info-number .badge { + font-size: 10px; + font-weight: normal; + line-height: 13px; + padding: 2px 6px; + position: absolute; + right: 2px; + top: 8px; } + +ul.to_do { + padding: 0; } + +ul.to_do li { + background: #f3f3f3; + border-radius: 3px; + position: relative; + padding: 7px; + margin-bottom: 5px; + list-style: none; } + +ul.to_do p { + margin: 0; } + +.dashboard-widget { + background: #f6f6f6; + border-top: 5px solid #79C3DF; + border-radius: 3px; + padding: 5px 10px 10px; } + +.dashboard-widget .dashboard-widget-title { + font-weight: normal; + border-bottom: 1px solid #c1cdcd; + margin: 0 0 10px 0; + padding-bottom: 5px; + padding-left: 40px; + line-height: 30px; } + +.dashboard-widget .dashboard-widget-title i { + font-size: 100%; + margin-left: -35px; + margin-right: 10px; + color: #33a1c9; + padding: 3px 6px; + border: 1px solid #abd9ea; + border-radius: 5px; + background: #fff; } + +ul.quick-list { + width: 45%; + padding-left: 0; + display: inline-block; } + +ul.quick-list li { + padding-left: 10px; + list-style: none; + margin: 0; + padding-bottom: 6px; + padding-top: 4px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; } + +ul.quick-list li i { + padding-right: 10px; + color: #757679; } + +.dashboard-widget-content { + padding-top: 9px; } + +.dashboard-widget-content .sidebar-widget { + width: 50%; + display: inline-block; + vertical-align: top; + background: #fff; + border: 1px solid #abd9ea; + border-radius: 5px; + text-align: center; + float: right; + padding: 2px; + margin-top: 10px; } + +.widget_summary { + width: 100%; + display: -ms-inline-flexbox; + display: inline-flex; } + +.widget_summary .w_left { + float: left; + text-align: left; } + +.widget_summary .w_center { + float: left; } + +.widget_summary .w_right { + float: left; + text-align: right; } + +.widget_summary .w_right span { + font-size: 20px; } + +.w_20 { + width: 20%; } + +.w_25 { + width: 25%; } + +.w_55 { + width: 55%; } + +h5.graph_title { + text-align: left; + margin-left: 10px; } + +h5.graph_title i { + margin-right: 10px; + font-size: 17px; } + +span.right { + float: right; + font-size: 14px !important; } + +.tile_info a { + text-overflow: ellipsis; } + +.sidebar-footer { + bottom: 0px; + clear: both; + display: block; + padding: 5px 0 0 0; + position: fixed; + width: 230px; + background: #2A3F54; } + +.sidebar-footer a { + padding: 7px 0 3px; + text-align: center; + width: 25%; + font-size: 17px; + display: block; + float: left; + background: #172D44; } + +.sidebar-footer a:hover { + background: #425567; } + +/** top tiles */ +.tile_count { + margin-bottom: 20px; + margin-top: 20px; } + +.tile_count .tile_stats_count { + border-bottom: 1px solid #D9DEE4; + padding: 0 10px 0 20px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + position: relative; } + +@media (min-width: 992px) { + footer { + margin-left: 0px; } } +@media (min-width: 992px) { + .tile_count .tile_stats_count { + margin-bottom: 10px; + border-bottom: 0; + padding-bottom: 10px; } } +.tile_count .tile_stats_count:before { + content: ""; + position: absolute; + left: 0; + height: 65px; + border-left: 2px solid #ADB2B5; + margin-top: 10px; } + +@media (min-width: 992px) { + .tile_count .tile_stats_count:first-child:before { + border-left: 0; } } +.tile_count .tile_stats_count .count { + font-size: 30px; + line-height: 47px; + font-weight: 600; } + +@media (min-width: 768px) { + .tile_count .tile_stats_count .count { + font-size: 40px; } } +@media (min-width: 992px) and (max-width: 1100px) { + .tile_count .tile_stats_count .count { + font-size: 30px; } } +.tile_count .tile_stats_count span { + font-size: 12px; } + +@media (min-width: 768px) { + .tile_count .tile_stats_count span { + font-size: 13px; } } +.tile_count .tile_stats_count .count_bottom i { + width: 12px; } + +/** /top tiles **/ +.dashboard_graph { + background: #fff; + padding: 7px 10px; } + +.dashboard_graph .col-md-9, .dashboard_graph .col-md-3 { + padding: 0; } + +a.user-profile { + color: #5E6974 !important; } + +.user-profile img { + width: 29px; + height: 29px; + border-radius: 50%; + margin-right: 10px; } + +ul.top_profiles { + height: 330px; + width: 100%; } + +ul.top_profiles li { + margin: 0; + padding: 3px 5px; } + +ul.top_profiles li:nth-child(odd) { + background-color: #eee; } + +.media .profile_thumb { + border: 1px solid; + width: 50px; + height: 50px; + margin: 5px 10px 5px 0; + border-radius: 50%; + padding: 9px 12px; } + +.media .profile_thumb i { + font-size: 30px; } + +.media .date { + background: #ccc; + width: 52px; + margin-right: 10px; + border-radius: 10px; + padding: 5px; } + +.media .date .month { + margin: 0; + text-align: center; + color: #fff; } + +.media .date .day { + text-align: center; + color: #fff; + font-size: 27px; + margin: 0; + line-height: 27px; + font-weight: bold; } + +.event .media-body a.title { + font-weight: bold; } + +.event .media-body p { + margin-bottom: 0; } + +h4.graph_title { + margin: 7px; + text-align: center; } + +/* ********* /widgets *************************************** */ +/* ********* iconts-display **************************** */ +.fontawesome-icon-list .fa-hover a:hover { + background-color: #ddd; + color: #fff; + text-decoration: none; } + +.fontawesome-icon-list .fa-hover a { + display: block; + line-height: 32px; + height: 32px; + padding-left: 10px; + border-radius: 4px; } + +.fontawesome-icon-list .fa-hover a:hover .fa { + font-size: 28px; + vertical-align: -6px; } + +.fontawesome-icon-list .fa-hover a .fa { + width: 32px; + font-size: 16px; + display: inline-block; + text-align: right; + margin-right: 10px; } + +.main_menu .fa { + width: 26px; + opacity: .99; + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + font-size: 18px; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } + +/* ********* /iconts-display **************************** */ +/** tile stats **/ +.tile-stats { + position: relative; + display: block; + margin-bottom: 12px; + border: 1px solid #E4E4E4; + -webkit-border-radius: 5px; + overflow: hidden; + padding-bottom: 5px; + -webkit-background-clip: padding-box; + -moz-border-radius: 5px; + -moz-background-clip: padding; + border-radius: 5px; + background-clip: padding-box; + background: #FFF; + transition: all 300ms ease-in-out; } + +.tile-stats:hover .icon i { + animation-name: tansformAnimation; + animation-duration: .5s; + animation-iteration-count: 1; + color: rgba(58, 58, 58, 0.41); + animation-timing-function: ease; + animation-fill-mode: forwards; + -webkit-animation-name: tansformAnimation; + -webkit-animation-duration: .5s; + -webkit-animation-iteration-count: 1; + -webkit-animation-timing-function: ease; + -webkit-animation-fill-mode: forwards; + -moz-animation-name: tansformAnimation; + -moz-animation-duration: .5s; + -moz-animation-iteration-count: 1; + -moz-animation-timing-function: ease; + -moz-animation-fill-mode: forwards; } + +.tile-stats .icon { + width: 20px; + height: 20px; + color: #BAB8B8; + position: absolute; + right: 53px; + top: 22px; + z-index: 1; } + +.tile-stats .icon i { + margin: 0; + font-size: 60px; + line-height: 0; + vertical-align: bottom; + padding: 0; } + +.tile-stats .count { + font-size: 38px; + font-weight: bold; + line-height: 1.65857; } + +.tile-stats .count, .tile-stats h3, .tile-stats p { + position: relative; + margin: 0; + margin-left: 10px; + z-index: 5; + padding: 0; } + +.tile-stats h3 { + color: #BAB8B8; } + +.tile-stats p { + margin-top: 5px; + font-size: 12px; } + +.tile-stats > .dash-box-footer { + position: relative; + text-align: center; + margin-top: 5px; + padding: 3px 0; + color: #fff; + color: rgba(255, 255, 255, 0.8); + display: block; + z-index: 10; + background: rgba(0, 0, 0, 0.1); + text-decoration: none; } + +.tile-stats > .dash-box-footer:hover { + color: #fff; + background: rgba(0, 0, 0, 0.15); } + +.tile-stats > .dash-box-footer:hover { + color: #fff; + background: rgba(0, 0, 0, 0.15); } + +table.tile_info { + padding: 10px 15px; } + +table.tile_info span.right { + margin-right: 0; + float: right; + position: absolute; + right: 4%; } + +.tile:hover { + text-decoration: none; } + +.tile_header { + border-bottom: transparent; + padding: 7px 15px; + margin-bottom: 15px; + background: #E7E7E7; } + +.tile_head h4 { + margin-top: 0; + margin-bottom: 5px; } + +.tiles-bottom { + padding: 5px 10px; + margin-top: 10px; + background: rgba(194, 194, 194, 0.3); + text-align: left; } + +/** /tile stats **/ +/** inbox **/ +a.star { + color: #428bca !important; } + +.mail_content { + background: none repeat scroll 0 0 #FFFFFF; + border-radius: 4px; + margin-top: 20px; + min-height: 500px; + padding: 10px 11px; + width: 100%; } + +.list-btn-mail { + margin-bottom: 15px; } + +.list-btn-mail.active { + border-bottom: 1px solid #39B3D7; + padding: 0 0 14px; } + +.list-btn-mail > i { + float: left; + font-size: 18px; + font-style: normal; + width: 33px; } + +.list-btn-mail > .cn { + background: none repeat scroll 0 0 #39B3D7; + border-radius: 12px; + color: #FFFFFF; + float: right; + font-style: normal; + padding: 0 5px; } + +.button-mail { + margin: 0 0 15px !important; + text-align: left; + width: 100%; } + +button, +.buttons, +.btn, +.modal-footer .btn + .btn { + margin-bottom: 5px; + margin-right: 5px; } + +.btn-group-vertical .btn, .btn-group .btn { + margin-bottom: 0; + margin-right: 0; } + +.mail_list_column { + border-left: 1px solid #DBDBDB; } + +.mail_view { + border-left: 1px solid #DBDBDB; } + +.mail_list { + width: 100%; + border-bottom: 1px solid #DBDBDB; + margin-bottom: 2px; + display: inline-block; } + +.mail_list .left { + width: 5%; + float: left; + margin-right: 3%; } + +.mail_list .right { + width: 90%; + float: left; } + +.mail_list h3 { + font-size: 15px; + font-weight: bold; + margin: 0px 0 6px; } + +.mail_list h3 small { + float: right; + color: #ADABAB; + font-size: 11px; + line-height: 20px; } + +.mail_list .badge { + padding: 3px 6px; + font-size: 8px; + background: #BAB7B7; } + +@media (max-width: 767px) { + .mail_list { + margin-bottom: 5px; + display: inline-block; } } +.mail_heading h4 { + font-size: 18px; + border-bottom: 1px solid #ddd; + padding-bottom: 10px; + margin-top: 20px; } + +.attachment { + margin-top: 30px; } + +.attachment ul { + width: 100%; + list-style: none; + padding-left: 0; + display: inline-block; + margin-bottom: 30px; } + +.attachment ul li { + float: left; + width: 150px; + margin-right: 10px; + margin-bottom: 10px; } + +.attachment ul li img { + height: 150px; + border: 1px solid #ddd; + padding: 5px; + margin-bottom: 10px; } + +.attachment ul li span { + float: right; } + +.attachment .file-name { + float: left; } + +.attachment .links { + width: 100%; + display: inline-block; } + +.compose { + padding: 0; + position: fixed; + bottom: 0; + right: 0; + background: #fff; + border: 1px solid #D9DEE4; + border-right: 0; + border-bottom: 0; + border-top-left-radius: 5px; + z-index: 9999; + display: none; } + +.compose .compose-header { + padding: 5px; + background: #169F85; + color: #fff; + border-top-left-radius: 5px; } + +.compose .compose-header .close { + text-shadow: 0 1px 0 #ffffff; + line-height: .8; } + +.compose .compose-body .editor.btn-toolbar { + margin: 0; } + +.compose .compose-body .editor-wrapper { + height: 100%; + min-height: 50px; + max-height: 180px; + border-radius: 0; + border-left: none; + border-right: none; + overflow: auto; } + +.compose .compose-footer { + padding: 10px; } + +/** /inbox **/ +/* ********* form design **************************** */ +.editor.btn-toolbar { + zoom: 1; + background: #F7F7F7; + margin: 5px 2px; + padding: 3px 0; + border: 1px solid #EFEFEF; } + +.input-group { + margin-bottom: 10px; } + +.ln_solid { + border-top: 1px solid #e5e5e5; + color: #ffffff; + background-color: #ffffff; + height: 1px; + margin: 20px 0; } + +span.section { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333; + border: 0; + border-bottom: 1px solid #e5e5e5; } + +.form-control { + border-radius: 0; + width: 100%; } + +.form-horizontal .control-label { + padding-top: 8px; } + +.form-control:focus { + border-color: #CCD0D7; + box-shadow: none !important; } + +legend { + font-size: 18px; + color: inherit; } + +.form-horizontal .form-group { + margin-right: 0; + margin-left: 0; } + +.form-control-feedback { + margin-top: 8px; + height: 23px; + color: #bbb; + line-height: 24px; + font-size: 15px; } + +.form-control-feedback.left { + border-right: 1px solid #ccc; + left: 13px; } + +.form-control-feedback.right { + border-left: 1px solid #ccc; + right: 13px; } + +.form-control.has-feedback-left { + padding-left: 45px; } + +.form-control.has-feedback-right { + padding-right: 45px; } + +.form-group { + margin-bottom: 10px; } + +.validate { + margin-top: 10px; } + +.invalid-form-error-message { + margin-top: 10px; + padding: 5px; } + +.invalid-form-error-message.filled { + border-left: 2px solid #E74C3C; } + +p.parsley-success { + color: #468847; + background-color: #DFF0D8; + border: 1px solid #D6E9C6; } + +p.parsley-error { + color: #B94A48; + background-color: #F2DEDE; + border: 1px solid #EED3D7; } + +ul.parsley-errors-list { + list-style: none; + color: #E74C3C; + padding-left: 0; } + +input.parsley-error, textarea.parsley-error, select.parsley-error { + background: #FAEDEC; + border: 1px solid #E85445; } + +.btn-group .parsley-errors-list { + display: none; } + +.bad input, .bad select, .bad textarea { + border: 1px solid #CE5454; + box-shadow: 0 0 4px -2px #CE5454; + position: relative; + left: 0; + -moz-animation: .7s 1 shake linear; + -webkit-animation: 0.7s 1 shake linear; } + +.item input, .item textarea { + transition: 0.42s; } + +/* alerts (when validation fails) */ +.item .alert { + float: left; + margin: 0 0 0 20px; + padding: 3px 10px; + color: #FFF; + border-radius: 3px 4px 4px 3px; + background-color: #CE5454; + max-width: 170px; + white-space: pre; + position: relative; + left: -15px; + opacity: 0; + z-index: 1; + transition: 0.15s ease-out; } + +.item .alert::after { + content: ''; + display: block; + height: 0; + width: 0; + border-color: transparent #CE5454 transparent transparent; + border-style: solid; + border-width: 11px 7px; + position: absolute; + left: -13px; + top: 1px; } + +.item.bad .alert { + left: 0; + opacity: 1; } + +.inl-bl { + display: inline-block; } + +.well .markup { + background: #fff; + color: #777; + position: relative; + padding: 45px 15px 15px; + margin: 15px 0 0 0; + background-color: #fff; + border-radius: 0 0 4px 4px; + box-shadow: none; } + +.well .markup::after { + content: "Example"; + position: absolute; + top: 15px; + left: 15px; + font-size: 12px; + font-weight: bold; + color: #bbb; + text-transform: uppercase; + letter-spacing: 1px; } + +/* ***** autocomplete ***** */ +.autocomplete-suggestions { + border: 1px solid #e4e4e4; + background: #F4F4F4; + cursor: default; + overflow: auto; } + +.autocomplete-suggestion { + padding: 2px 5px; + font-size: 1.2em; + white-space: nowrap; + overflow: hidden; } + +.autocomplete-selected { + background: #f0f0f0; } + +.autocomplete-suggestions strong { + font-weight: normal; + color: #3399ff; + font-weight: bolder; } + +/* ***** /autocomplete *****/ +/* ***** buttons ********/ +.btn { + border-radius: 3px; } + +a.btn-success, a.btn-primary, a.btn-warning, a.btn-danger { + color: #fff; } + +.btn-success { + background: #26B99A; + border: 1px solid #169F85; } + +.btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active, .open .dropdown-toggle.btn-success { + background: #169F85; } + +.btn-dark { + color: #E9EDEF; + background-color: #4B5F71; + border-color: #364B5F; } + +.btn-dark:hover, .btn-dark:focus, .btn-dark:active, .btn-dark.active, .open .dropdown-toggle.btn-dark { + color: #FFFFFF; + background-color: #394D5F; + border-color: #394D5F; } + +.btn-round { + border-radius: 30px; } + +.btn.btn-app { + position: relative; + padding: 15px 5px; + margin: 0 0 10px 10px; + min-width: 80px; + height: 60px; + box-shadow: none; + border-radius: 0; + text-align: center; + color: #666; + border: 1px solid #ddd; + background-color: #fafafa; + font-size: 12px; } + +.btn.btn-app > .fa, .btn.btn-app > .glyphicon, .btn.btn-app > .ion { + font-size: 20px; + display: block; } + +.btn.btn-app:hover { + background: #f4f4f4; + color: #444; + border-color: #aaa; } + +.btn.btn-app:active, .btn.btn-app:focus { + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); } + +.btn.btn-app > .badge { + position: absolute; + top: -3px; + right: -10px; + font-size: 10px; + font-weight: 400; } + +/* ***** /buttons *******/ +/* ********* /form design **************************** */ +/* ********* form textarea **************************** */ +textarea { + padding: 10px; + vertical-align: top; + width: 200px; } + +textarea:focus { + outline-style: solid; + outline-width: 2px; } + +.btn_ { + display: inline-block; + padding: 3px 9px; + margin-bottom: 0; + font-size: 14px; + line-height: 20px; + text-align: center; + vertical-align: middle; + cursor: pointer; + color: #333333; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + background-color: #f5f5f5; + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + border: 1px solid #cccccc; + border-bottom-color: #b3b3b3; + border-radius: 4px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } + +/* ********* /form textarea **************************** */ +/* ********* glyphicons **************************** */ +.bs-glyphicons { + margin: 0 -10px 20px; + overflow: hidden; } + +.bs-glyphicons-list { + padding-left: 0; + list-style: none; } + +.bs-glyphicons li { + float: left; + width: 25%; + height: 115px; + padding: 10px; + font-size: 10px; + line-height: 1.4; + text-align: center; + background-color: #f9f9f9; + border: 1px solid #fff; } + +.bs-glyphicons .glyphicon { + margin-top: 5px; + margin-bottom: 10px; + font-size: 24px; } + +.bs-glyphicons .glyphicon-class { + display: block; + text-align: center; + word-wrap: break-word; } + +.bs-glyphicons li:hover { + color: #fff; + background-color: #1ABB9C; } + +@media (min-width: 768px) { + .bs-glyphicons { + margin-right: 0; + margin-left: 0; } + + .bs-glyphicons li { + width: 12.5%; + font-size: 12px; } } +/* ********* /glyphicons **************************** */ +/* ********* form tags input **************************** */ +.tagsinput { + border: 1px solid #CCC; + background: #FFF; + padding: 6px 6px 0; + width: 300px; + overflow-y: auto; } + +span.tag { + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + display: block; + float: left; + padding: 5px 9px; + text-decoration: none; + background: #1ABB9C; + color: #F1F6F7; + margin-right: 5px; + font-weight: 500; + margin-bottom: 5px; + font-family: helvetica; } + +span.tag a { + color: #F1F6F7 !important; } + +.tagsinput span.tag a { + font-weight: bold; + color: #82ad2b; + text-decoration: none; + font-size: 11px; } + +.tagsinput input { + width: 80px; + margin: 0px; + font-family: helvetica; + font-size: 13px; + border: 1px solid transparent; + padding: 3px; + background: transparent; + color: #000; + outline: 0px; } + +.tagsinput div { + display: block; + float: left; } + +.tags_clear { + clear: both; + width: 100%; + height: 0px; } + +.not_valid { + background: #FBD8DB !important; + color: #90111A !important; } + +/* ********* /form tags input **************************** */ +/** Tabs **/ +ul.bar_tabs { + overflow: visible; + background: #F5F7FA; + height: 25px; + margin: 21px 0 14px; + padding-left: 14px; + position: relative; + z-index: 1; + width: 100%; + border-bottom: 1px solid #E6E9ED; } + +ul.bar_tabs > li { + border: 1px solid #E6E9ED; + color: #333 !important; + margin-top: -17px; + margin-left: 8px; + background: #fff; + border-bottom: none; + border-radius: 4px 4px 0 0; } + +ul.bar_tabs > li.active { + border-right: 6px solid #D3D6DA; + border-top: 0; + margin-top: -15px; } + +ul.bar_tabs > li a { + padding: 10px 17px; + background: #F5F7FA; + margin: 0; + border-top-right-radius: 0; } + +ul.bar_tabs > li a:hover { + border: 1px solid transparent; } + +ul.bar_tabs > li.active a { + border-bottom: none; } + +ul.bar_tabs.right { + padding-right: 14px; } + +ul.bar_tabs.right li { + float: right; } + +a:focus { + outline: none; } + +/** /Tabs **/ +/* ********* timeline **************************** */ +ul.timeline li { + position: relative; + border-bottom: 1px solid #e8e8e8; + clear: both; } + +.timeline .block { + margin: 0; + border-left: 3px solid #e8e8e8; + overflow: visible; + padding: 10px 15px; + margin-left: 105px; } + +.timeline.widget { + min-width: 0; + max-width: inherit; } + +.timeline.widget .block { + margin-left: 5px; } + +.timeline .tags { + position: absolute; + top: 15px; + left: 0; + width: 84px; } + +.timeline .tag { + display: block; + height: 30px; + font-size: 13px; + padding: 8px; } + +.timeline .tag span { + display: block; + overflow: hidden; + width: 100%; + white-space: nowrap; + text-overflow: ellipsis; } + +.tag { + line-height: 1; + background: #1ABB9C; + color: #fff !important; } + +.tag:after { + content: " "; + height: 30px; + width: 0; + position: absolute; + left: 100%; + top: 0; + margin: 0; + pointer-events: none; + border-top: 14px solid transparent; + border-bottom: 14px solid transparent; + border-left: 11px solid #1ABB9C; } + +.timeline h2.title { + position: relative; + font-size: 16px; + margin: 0; } + +.timeline h2.title:before { + content: ""; + position: absolute; + left: -23px; + top: 3px; + display: block; + width: 14px; + height: 14px; + border: 3px solid #d2d3d2; + border-radius: 14px; + background: #f9f9f9; } + +.timeline .byline { + padding: .25em 0; } + +.byline { + -webkit-font-smoothing: antialiased; + font-style: italic; + font-size: .9375em; + line-height: 1.3; + color: #aab6aa; } + +ul.social li { + border: 0; } + +/* ********* /timeline **************************** */ +/* ********* profile/social **************************** */ +.social-sidebar, .social-body { + float: right; } + +.social-sidebar { + background: #EDEDED; + width: 22%; } + +.social-body { + border: 1px solid #ccc; + width: 78%; } + +.thumb img { + width: 50px; + height: 50px; + border-radius: 50%; } + +.chat .thumb img { + width: 27px; + height: 27px; + border-radius: 50%; } + +.chat .status { + float: left; + margin: 16px 0 0 -16px; + font-size: 14px; + font-weight: bold; + width: 12px; + height: 12px; + display: block; + border: 2px solid #FFF; + z-index: 12312; + border-radius: 50%; } + +.chat .status.online { + background: #1ABB9C; } + +.chat .status.away { + background: #F39C12; } + +.chat .status.offline { + background: #ccc; } + +.chat .media-body { + padding-top: 5px; } + +/* ********* /profile/social **************************** */ +/* ********* widgets **************************** */ +.dashboard_graph .x_title { + padding: 5px 5px 7px; } + +.dashboard_graph .x_title h3 { + margin: 0; + font-weight: normal; } + +.chart { + position: relative; + display: inline-block; + width: 110px; + height: 110px; + margin-top: 5px; + margin-bottom: 5px; + text-align: center; } + +.chart canvas { + position: absolute; + top: 0; + left: 0; } + +.percent { + display: inline-block; + line-height: 110px; + z-index: 2; + font-size: 18px; } + +.percent:after { + content: '%'; + margin-left: 0.1em; + font-size: .8em; } + +.angular { + margin-top: 100px; } + +.angular .chart { + margin-top: 0; } + +.widget { + min-width: 250px; + max-width: 310px; } + +.widget_tally_box .btn-group button { + text-align: center; } + +.widget_tally_box .btn-group button { + color: inherit; + font-weight: 500; + background-color: #f5f5f5; + border: 1px solid #e7e7e7; } + +ul.widget_tally, ul.widget_tally li { + width: 100%; } + +ul.widget_tally li { + padding: 2px 10px; + border-bottom: 1px solid #ECECEC; + padding-bottom: 4px; } + +ul.widget_tally .month { + width: 70%; + float: left; } + +ul.widget_tally .count { + width: 30%; + float: left; + text-align: right; } + +.pie_bg { + border-bottom: 1px solid rgba(101, 204, 182, 0.16); + padding-bottom: 15px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + padding-bottom: 10px; + box-shadow: 0 4px 6px -6px #222; } + +.widget_tally_box .flex { + display: -ms-flexbox; + display: flex; } + +ul.widget_profile_box { + width: 100%; + height: 42px; + padding: 3px; + background: #ececec; + margin-top: 40px; + margin-left: 1px; } + +ul.widget_profile_box li:first-child { + width: 25%; + float: left; } + +ul.widget_profile_box li:first-child a { + float: left; } + +ul.widget_profile_box li:last-child { + width: 25%; + float: right; } + +ul.widget_profile_box li:last-child a { + float: right; } + +ul.widget_profile_box li a { + font-size: 22px; + text-align: center; + width: 35px; + height: 35px; + border: 1px solid rgba(52, 73, 94, 0.44); + display: block; + border-radius: 50%; + padding: 0px; } + +ul.widget_profile_box li a:hover { + color: #1ABB9C !important; + border: 1px solid #26b99a; } + +ul.widget_profile_box li .profile_img { + width: 85px; + height: 85px; + margin: 0; + margin-top: -28px; } + +.widget_tally_box p, .widget_tally_box span { + text-align: center; } + +.widget_tally_box .name { + text-align: center; + margin: 25px; } + +.widget_tally_box .name_title { + text-align: center; + margin: 5px; } + +.widget_tally_box ul.legend { + margin: 0; } + +.widget_tally_box ul.legend p, .widget_tally_box ul.legend span { + text-align: left; } + +.widget_tally_box ul.legend li .icon { + font-size: 20px; + float: left; + width: 14px; } + +.widget_tally_box ul.legend li .name { + font-size: 14px; + margin: 5px 0 0 14px; + text-overflow: ellipsis; + float: left; } + +.widget_tally_box ul.legend p { + display: inline-block; + margin: 0; } + +.widget_tally_box ul.verticle_bars li { + height: 140px; + width: 23%; } + +.widget .verticle_bars li .progress.vertical.progress_wide { + width: 65%; } + +ul.count2 { + width: 100%; + margin-left: 1px; + border: 1px solid #ddd; + border-left: 0; + border-right: 0; + padding: 10px 0; } + +ul.count2 li { + width: 30%; + text-align: center; } + +ul.count2 li h3 { + font-weight: 400; + margin: 0; } + +ul.count2 li span { + font-weight: 300; } + +/* ********* /widgets **************************** */ +.divider { + border-bottom: 1px solid #ddd; + margin: 10px; } + +.divider-dashed { + border-top: 1px dashed #e7eaec; + background-color: #ffffff; + height: 1px; + margin: 10px 0; } + +ul.messages { + padding: 0; + list-style: none; } + +ul.messages li, .tasks li { + border-bottom: 1px dotted #e6e6e6; + padding: 8px 0; } + +ul.messages li img.avatar, img.avatar { + height: 32px; + width: 32px; + float: left; + display: inline-block; + border-radius: 2px; + padding: 2px; + background: #f7f7f7; + border: 1px solid #e6e6e6; } + +ul.messages li .message_date { + float: right; + text-align: right; } + +ul.messages li .message_wrapper { + margin-left: 50px; + margin-right: 40px; } + +ul.messages li .message_wrapper h4.heading { + font-weight: 600; + margin: 0; + cursor: pointer; + margin-bottom: 10px; + line-height: 100%; } + +ul.messages li .message_wrapper blockquote { + padding: 0px 10px; + margin: 0; + border-left: 5px solid #eee; } + +ul.user_data li { + margin-bottom: 6px; } + +ul.user_data li p { + margin-bottom: 0; } + +ul.user_data li .progress { + width: 90%; } + +.project_progress .progress { + margin-bottom: 3px !important; + margin-top: 5px; } + +.projects .list-inline { + margin: 0; } + +.profile_title { + background: #F5F7FA; + border: 0; + padding: 7px 0; + display: -ms-flexbox; + display: flex; } + +ul.stats-overview { + border-bottom: 1px solid #e8e8e8; + padding-bottom: 10px; + margin-bottom: 10px; } + +ul.stats-overview li { + display: inline-block; + text-align: center; + padding: 0 15px; + width: 30%; + font-size: 14px; + border-right: 1px solid #e8e8e8; } + +ul.stats-overview li:last-child { + border-right: 0; } + +ul.stats-overview li .name { + font-size: 12px; } + +ul.stats-overview li .value { + font-size: 14px; + font-weight: bold; + display: block; } + +ul.stats-overview li:first-child { + padding-left: 0; } + +ul.project_files li { + margin-bottom: 5px; } + +ul.project_files li a i { + width: 20px; } + +.project_detail p { + margin-bottom: 10px; } + +.project_detail p.title { + font-weight: bold; + margin-bottom: 0; } + +.avatar img { + border-radius: 50%; + max-width: 45px; } + +/* ********* pricing **************************** */ +.pricing { + background: #fff; } + +.pricing .title { + background: #1ABB9C; + height: 110px; + color: #fff; + padding: 15px 0 0; + text-align: center; } + +.pricing .title h2 { + text-transform: capitalize; + font-size: 18px; + border-radius: 5px 5px 0 0; + margin: 0; + font-weight: 400; } + +.pricing .title h1 { + font-size: 30px; + margin: 12px; } + +.pricing .title span { + background: rgba(51, 51, 51, 0.28); + padding: 2px 5px; } + +.pricing_features { + background: #FAFAFA; + padding: 20px 15px; + min-height: 230px; + font-size: 13.5px; } + +.pricing_features ul li { + margin-top: 10px; } + +.pricing_footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + text-align: center; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; } + +.pricing_footer p { + font-size: 13px; + padding: 10px 0 2px; + display: block; } + +.ui-ribbon-container { + position: relative; } + +.ui-ribbon-container .ui-ribbon-wrapper { + position: absolute; + overflow: hidden; + width: 85px; + height: 88px; + top: -3px; + right: -3px; } + +.ui-ribbon-container.ui-ribbon-primary .ui-ribbon { + background-color: #5b90bf; } + +.ui-ribbon-container .ui-ribbon { + position: relative; + display: block; + text-align: center; + font-size: 15px; + font-weight: 700; + color: #fff; + transform: rotate(45deg); + padding: 7px 0; + left: -5px; + top: 15px; + width: 120px; + line-height: 20px; + background-color: #555; + box-shadow: 0 0 3px rgba(0, 0, 0, 0.3); } + +.ui-ribbon-container.ui-ribbon-primary .ui-ribbon:after, .ui-ribbon-container.ui-ribbon-primary .ui-ribbon:before { + border-top: 2px solid #5b90bf; } + +.ui-ribbon-container .ui-ribbon:before { + left: 0; + bottom: -1px; } + +.ui-ribbon-container .ui-ribbon:before { + right: 0; } + +.ui-ribbon-container .ui-ribbon:after, .ui-ribbon-container .ui-ribbon:before { + position: absolute; + content: " "; + line-height: 0; + border-top: 2px solid #555; + border-left: 2px solid transparent; + border-right: 2px solid transparent; } + +/* ********* /pricing **************************** */ +/* ********* media gallery **************************** */ +.thumbnail .image { + height: 120px; + overflow: hidden; } + +.caption { + padding: 9px 5px; + background: #F7F7F7; } + +.caption p { + margin-bottom: 5px; } + +.thumbnail { + height: 190px; + overflow: hidden; } + +.view { + overflow: hidden; + position: relative; + text-align: center; + box-shadow: 1px 1px 2px #e6e6e6; + cursor: default; } + +.view .mask, .view .content { + position: absolute; + width: 100%; + overflow: hidden; + top: 0; + left: 0; } + +.view img { + display: block; + position: relative; } + +.view .tools { + text-transform: uppercase; + color: #fff; + text-align: center; + position: relative; + font-size: 17px; + padding: 3px; + background: rgba(0, 0, 0, 0.35); + margin: 43px 0 0 0; } + +.mask.no-caption .tools { + margin: 90px 0 0 0; } + +.view .tools a { + display: inline-block; + color: #FFF; + font-size: 18px; + font-weight: 400; + padding: 0 4px; } + +.view p { + font-family: Georgia, serif; + font-style: italic; + font-size: 12px; + position: relative; + color: #fff; + padding: 10px 20px 20px; + text-align: center; } + +.view a.info { + display: inline-block; + text-decoration: none; + padding: 7px 14px; + background: #000; + color: #fff; + text-transform: uppercase; + box-shadow: 0 0 1px #000; } + +.view-first img { + transition: all 0.2s linear; } + +.view-first .mask { + opacity: 0; + background-color: rgba(0, 0, 0, 0.5); + transition: all 0.4s ease-in-out; } + +.view-first .tools { + transform: translateY(-100px); + opacity: 0; + transition: all 0.2s ease-in-out; } + +.view-first p { + transform: translateY(100px); + opacity: 0; + transition: all 0.2s linear; } + +.view-first:hover img { + transform: scale(1.1); } + +.view-first:hover .mask { + opacity: 1; } + +.view-first:hover .tools, .view-first:hover p { + opacity: 1; + transform: translateY(0px); } + +.view-first:hover p { + transition-delay: 0.1s; } + +/* ********* /media gallery **************************** */ +/* ********* verticle tabs **************************** */ +/*! + * bootstrap-vertical-tabs - v1.2.1 + * https://dbtek.github.io/bootstrap-vertical-tabs + * 2014-11-07 + * Copyright (c) 2014 İsmail Demirbilek + * License: MIT + */ +.tabs-left, .tabs-right { + border-bottom: none; + padding-top: 2px; } + +.tabs-left { + border-right: 1px solid #F7F7F7; } + +.tabs-right { + border-left: 1px solid #F7F7F7; } + +.tabs-left > li, .tabs-right > li { + float: none; + margin-bottom: 2px; } + +.tabs-left > li { + margin-right: -1px; } + +.tabs-right > li { + margin-left: -1px; } + +.tabs-left > li.active > a, .tabs-left > li.active > a:hover, .tabs-left > li.active > a:focus { + border-bottom-color: #F7F7F7; + border-right-color: transparent; } + +.tabs-right > li.active > a, .tabs-right > li.active > a:hover, .tabs-right > li.active > a:focus { + border-bottom: 1px solid #F7F7F7; + border-left-color: transparent; } + +.tabs-left > li > a { + border-radius: 4px 0 0 4px; + margin-right: 0; + display: block; + background: #F7F7F7; + text-overflow: ellipsis; + overflow: hidden; } + +.tabs-right > li > a { + border-radius: 0 4px 4px 0; + margin-right: 0; + background: #F7F7F7; + text-overflow: ellipsis; + overflow: hidden; } + +.sideways { + margin-top: 50px; + border: none; + position: relative; } + +.sideways > li { + height: 20px; + width: 120px; + margin-bottom: 100px; } + +.sideways > li > a { + border-bottom: 1px solid #ddd; + border-right-color: transparent; + text-align: center; + border-radius: 4px 4px 0px 0px; } + +.sideways > li.active > a, .sideways > li.active > a:hover, .sideways > li.active > a:focus { + border-bottom-color: transparent; + border-right-color: #ddd; + border-left-color: #ddd; } + +.sideways.tabs-left { + left: -50px; } + +.sideways.tabs-right { + right: -50px; } + +.sideways.tabs-right > li { + transform: rotate(90deg); } + +.sideways.tabs-left > li { + transform: rotate(-90deg); } + +/* ********* /verticle tabs **************************** */ +/* ********* moris **************************** */ +.morris-hover { + position: absolute; + z-index: 1000; } + +.morris-hover.morris-default-style { + padding: 6px; + color: #666; + background: rgba(243, 242, 243, 0.8); + border: solid 2px rgba(195, 194, 196, 0.8); + font-family: sans-serif; + font-size: 12px; + text-align: center; } + +.morris-hover.morris-default-style .morris-hover-row-label { + font-weight: bold; + margin: 0.25em 0; } + +.morris-hover.morris-default-style .morris-hover-point { + white-space: nowrap; + margin: 0.1em 0; } + +/* ********* /moris **************************** */ +/* ********* ecommerce **************************** */ +.price { + font-size: 40px; + font-weight: 400; + color: #26B99A; + margin: 0; } + +.prod_title { + border-bottom: 1px solid #DFDFDF; + padding-bottom: 5px; + margin: 30px 0; + font-size: 20px; + font-weight: 400; } + +.product-image img { + width: 90%; } + +.prod_color li { + margin: 0 10px; } + +.prod_color li p { + margin-bottom: 0; } + +.prod_size li { + padding: 0; } + +.prod_color .color { + width: 25px; + height: 25px; + border: 2px solid rgba(51, 51, 51, 0.28) !important; + padding: 2px; + border-radius: 50px; } + +.product_gallery a { + width: 100px; + height: 100px; + float: left; + margin: 10px; + border: 1px solid #e5e5e5; } + +.product_gallery a img { + width: 100%; + margin-top: 15px; } + +.product_price { + margin: 20px 0; + padding: 5px 10px; + background-color: #FFFFFF; + text-align: left; + border: 2px dashed #E0E0E0; } + +.price-tax { + font-size: 18px; } + +.product_social { + margin: 20px 0; } + +.product_social ul li a i { + font-size: 35px; } + +/* ********* /ecommerce **************************** */ +/** login **/ +.login { + background: #F7F7F7; } + +.login .fa-paw { + font-size: 26px; } + +a.hiddenanchor { + display: none; } + +.login_wrapper { + right: 0px; + margin: 0px auto; + margin-top: 5%; + max-width: 350px; + position: relative; } + +.registration_form, .login_form { + position: absolute; + top: 0px; + width: 100%; } + +.registration_form { + z-index: 21; + opacity: 0; + width: 100%; } + +.login_form { + z-index: 22; } + +#signup:target ~ .login_wrapper .registration_form, #signin:target ~ .login_wrapper .login_form { + z-index: 22; + animation-name: fadeInLeft; + animation-delay: .1s; } + +#signup:target ~ .login_wrapper .login_form, #signin:target ~ .login_wrapper .registration_form { + animation-name: fadeOutLeft; } + +.animate { + -webkit-animation-duration: 0.5s; + -webkit-animation-timing-function: ease; + -webkit-animation-fill-mode: both; + -moz-animation-duration: 0.5s; + -moz-animation-timing-function: ease; + -moz-animation-fill-mode: both; + -o-animation-duration: 0.5s; + -o-animation-timing-function: ease; + -o-animation-fill-mode: both; + -ms-animation-duration: 0.5s; + -ms-animation-timing-function: ease; + -ms-animation-fill-mode: both; + animation-duration: 0.5s; + animation-timing-function: ease; + animation-fill-mode: both; } + +/** /login **/ +/** signup **/ +.login_box { + padding: 20px; + margin: auto; } + +.left { + float: left; } + +.alignleft { + float: left; + margin-right: 15px; } + +.alignright { + float: right; + margin-left: 15px; } + +.clearfix:after, form:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; } + +.login_content { + margin: 0 auto; + padding: 25px 0 0; + position: relative; + text-align: center; + text-shadow: 0 1px 0 #fff; + min-width: 280px; } + +.login_content a, +.login_content .btn-default:hover { + text-decoration: none; } + +.login_content a:hover { + text-decoration: underline; } + +.login_content h1 { + font: normal 25px Helvetica, Arial, sans-serif; + letter-spacing: -0.05em; + line-height: 20px; + margin: 10px 0 30px; } + +.login_content h1:before, .login_content h1:after { + content: ""; + height: 1px; + position: absolute; + top: 10px; + width: 27%; } + +.login_content h1:after { + background: #7e7e7e; + background: linear-gradient(left, #7e7e7e 0%, white 100%); + right: 0; } + +.login_content h1:before { + background: #7e7e7e; + background: linear-gradient(right, #7e7e7e 0%, white 100%); + left: 0; } + +.login_content h1:before, .login_content h1:after { + content: ""; + height: 1px; + position: absolute; + top: 10px; + width: 20%; } + +.login_content h1:after { + background: #7e7e7e; + background: linear-gradient(left, #7e7e7e 0%, white 100%); + right: 0; } + +.login_content h1:before { + background: #7e7e7e; + background: linear-gradient(right, #7e7e7e 0%, white 100%); + left: 0; } + +.login_content form { + margin: 20px 0; + position: relative; } + +.login_content form input[type="text"], .login_content form input[type="email"], .login_content form input[type="password"] { + border-radius: 3px; + -ms-box-shadow: 0 1px 0 #fff, 0 -2px 5px rgba(0, 0, 0, 0.08) inset; + -o-box-shadow: 0 1px 0 #fff, 0 -2px 5px rgba(0, 0, 0, 0.08) inset; + box-shadow: 0 1px 0 #fff, 0 -2px 5px rgba(0, 0, 0, 0.08) inset; + border: 1px solid #c8c8c8; + color: #777; + margin: 0 0 20px; + width: 100%; } + +.login_content form input[type="text"]:focus, .login_content form input[type="email"]:focus, .login_content form input[type="password"]:focus { + -ms-box-shadow: 0 0 2px #ed1c24 inset; + -o-box-shadow: 0 0 2px #ed1c24 inset; + box-shadow: 0 0 2px #A97AAD inset; + background-color: #fff; + border: 1px solid #A878AF; + outline: none; } + +#username { + background-position: 10px 10px !important; } + +#password { + background-position: 10px -53px !important; } + +.login_content form div a { + font-size: 12px; + margin: 10px 15px 0 0; } + +.reset_pass { + margin-top: 10px !important; } + +.login_content div .reset_pass { + margin-top: 13px !important; + margin-right: 39px; + float: right; } + +.separator { + border-top: 1px solid #D8D8D8; + margin-top: 10px; + padding-top: 10px; } + +.button { + background: #f7f9fa; + background: linear-gradient(top, #f7f9fa 0%, #f0f0f0 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f7f9fa', endColorstr='#f0f0f0', GradientType=0); + -ms-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset; + -o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset; + border-radius: 0 0 5px 5px; + border-top: 1px solid #CFD5D9; + padding: 15px 0; } + +.login_content form input[type="submit"], #content form .submit { + float: left; + margin-left: 38px; } + +.button a { + background: url(http://cssdeck.com/uploads/media/items/8/8bcLQqF.png) 0 -112px no-repeat; + color: #7E7E7E; + font-size: 17px; + padding: 2px 0 2px 40px; + text-decoration: none; + transition: all 0.3s ease; } + +.button a:hover { + background-position: 0 -135px; + color: #00aeef; } + +header { + width: 100%; } + +/** signup **/ +/** NProgress **/ +#nprogress .bar { + background: #1ABB9C; } + +#nprogress .peg { + box-shadow: 0 0 10px #1ABB9C, 0 0 5px #1ABB9C; } + +#nprogress .spinner-icon { + border-top-color: #1ABB9C; + border-left-color: #1ABB9C; } + +/** /NProgress **/ +/** bootstrap-wysiwyg **/ +.editor-wrapper { + min-height: 250px; + background-color: white; + border-collapse: separate; + border: 1px solid #cccccc; + padding: 4px; + box-sizing: content-box; + box-shadow: rgba(0, 0, 0, 0.07451) 0px 1px 1px 0px inset; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; + overflow: scroll; + outline: none; } + +.voiceBtn { + width: 20px; + color: transparent; + background-color: transparent; + transform: scale(2, 2); + -webkit-transform: scale(2, 2); + -moz-transform: scale(2, 2); + border: transparent; + cursor: pointer; + box-shadow: none; + -webkit-box-shadow: none; } + +div[data-role="editor-toolbar"] { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + +.dropdown-menu a { + cursor: pointer; } + +/** /bootstrap-wysiwyg **/ +/** Select2 **/ +.select2-container--default .select2-selection--single, +.select2-container--default .select2-selection--multiple { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 0; + min-height: 38px; } + +.select2-container--default .select2-selection--single .select2-selection__rendered { + color: #73879C; + padding-top: 5px; } + +.select2-container--default .select2-selection--multiple .select2-selection__rendered { + padding-top: 3px; } + +.select2-container--default .select2-selection--single .select2-selection__arrow { + height: 36px; } + +.select2-container--default .select2-selection--multiple .select2-selection__choice, +.select2-container--default .select2-selection--multiple .select2-selection__clear { + margin-top: 2px; + border: none; + border-radius: 0; + padding: 3px 5px; } + +.select2-container--default.select2-container--focus .select2-selection--multiple { + border: 1px solid #ccc; } + +/** /Select2 **/ +/** Switchery **/ +.switchery { + width: 32px; + height: 20px; } + +.switchery > small { + width: 20px; + height: 20px; } + +/** /Switchery **/ +/** Normalize.css **/ +fieldset { + border: none; + margin: 0; + padding: 0; } + +/** /Normalize.css **/ +/** Cropper **/ +.cropper .img-container, +.cropper .img-preview { + background-color: #f7f7f7; + width: 100%; + text-align: center; } + +.cropper .img-container { + min-height: 200px; + max-height: 516px; + margin-bottom: 20px; } + +@media (min-width: 768px) { + .cropper .img-container { + min-height: 516px; } } +.cropper .img-container > img { + max-width: 100%; } + +.cropper .docs-preview { + margin-right: -15px; } + +.cropper .img-preview { + float: left; + margin-right: 10px; + margin-bottom: 10px; + overflow: hidden; } + +.cropper .img-preview > img { + max-width: 100%; } + +.cropper .preview-lg { + width: 263px; + height: 148px; } + +.cropper .preview-md { + width: 139px; + height: 78px; } + +.cropper .preview-sm { + width: 69px; + height: 39px; } + +.cropper .preview-xs { + width: 35px; + height: 20px; + margin-right: 0; } + +.cropper .docs-data > .input-group { + margin-bottom: 10px; } + +.cropper .docs-data > .input-group > label { + min-width: 80px; } + +.cropper .docs-data > .input-group > span { + min-width: 50px; } + +.cropper .docs-buttons > .btn, +.cropper .docs-buttons > .btn-group, +.cropper .docs-buttons > .form-control { + margin-right: 5px; + margin-bottom: 10px; } + +.cropper .docs-toggles > .btn, +.cropper .docs-toggles > .btn-group, +.cropper .docs-toggles > .dropdown { + margin-bottom: 10px; } + +.cropper .docs-tooltip { + display: block; + margin: -6px -12px; + padding: 6px 12px; } + +.cropper .docs-tooltip > .icon { + margin: 0 -3px; + vertical-align: top; } + +.cropper .tooltip-inner { + white-space: normal; } + +.cropper .btn-upload .tooltip-inner, +.cropper .btn-toggle .tooltip-inner { + white-space: nowrap; } + +.cropper .btn-toggle { + padding: 6px; } + +.cropper .btn-toggle > .docs-tooltip { + margin: -6px; + padding: 6px; } + +@media (max-width: 400px) { + .cropper .btn-group-crop { + margin-right: -15px !important; } + + .cropper .btn-group-crop > .btn { + padding-left: 5px; + padding-right: 5px; } + + .cropper .btn-group-crop .docs-tooltip { + margin-left: -5px; + margin-right: -5px; + padding-left: 5px; + padding-right: 5px; } } +.cropper .docs-options .dropdown-menu { + width: 100%; } + +.cropper .docs-options .dropdown-menu > li { + padding: 3px 20px; } + +.cropper .docs-options .dropdown-menu > li:hover { + background-color: #f7f7f7; } + +.cropper .docs-options .dropdown-menu > li > label { + display: block; } + +.cropper .docs-cropped .modal-body { + text-align: center; } + +.cropper .docs-cropped .modal-body > img, +.cropper .docs-cropped .modal-body > canvas { + max-width: 100%; } + +.cropper .docs-diagram .modal-dialog { + max-width: 352px; } + +.cropper .docs-cropped canvas { + max-width: 100%; } + +/** /Cropper **/ +/** jQuery Smart Wizard **/ +.form_wizard .stepContainer { + display: block; + position: relative; + margin: 0; + padding: 0; + border: 0 solid #CCC; + overflow-x: hidden; } + +.wizard_horizontal ul.wizard_steps { + display: table; + list-style: none; + position: relative; + width: 100%; + margin: 0 0 20px; } + +.wizard_horizontal ul.wizard_steps li { + display: table-cell; + text-align: center; } + +.wizard_horizontal ul.wizard_steps li a, .wizard_horizontal ul.wizard_steps li:hover { + display: block; + position: relative; + -moz-opacity: 1; + filter: alpha(opacity=100); + opacity: 1; + color: #666; } + +.wizard_horizontal ul.wizard_steps li a:before { + content: ""; + position: absolute; + height: 4px; + background: #ccc; + top: 20px; + width: 100%; + z-index: 4; + left: 0; } + +.wizard_horizontal ul.wizard_steps li a.disabled .step_no { + background: #ccc; } + +.wizard_horizontal ul.wizard_steps li a .step_no { + width: 40px; + height: 40px; + line-height: 40px; + border-radius: 100px; + display: block; + margin: 0 auto 5px; + font-size: 16px; + text-align: center; + position: relative; + z-index: 5; } + +.wizard_horizontal ul.wizard_steps li a.selected:before, .step_no { + background: #34495E; + color: #fff; } + +.wizard_horizontal ul.wizard_steps li a.done:before, .wizard_horizontal ul.wizard_steps li a.done .step_no { + background: #1ABB9C; + color: #fff; } + +.wizard_horizontal ul.wizard_steps li:first-child a:before { + left: 50%; } + +.wizard_horizontal ul.wizard_steps li:last-child a:before { + right: 50%; + width: 50%; + left: auto; } + +.wizard_verticle .stepContainer { + width: 80%; + float: left; + padding: 0 10px; } + +.actionBar { + width: 100%; + border-top: 1px solid #ddd; + padding: 10px 5px; + text-align: right; + margin-top: 10px; } + +.actionBar .buttonDisabled { + cursor: not-allowed; + pointer-events: none; + opacity: .65; + filter: alpha(opacity=65); + box-shadow: none; } + +.actionBar a { + margin: 0 3px; } + +.wizard_verticle .wizard_content { + width: 80%; + float: left; + padding-left: 20px; } + +.wizard_verticle ul.wizard_steps { + display: table; + list-style: none; + position: relative; + width: 20%; + float: left; + margin: 0 0 20px; } + +.wizard_verticle ul.wizard_steps li { + display: list-item; + text-align: center; } + +.wizard_verticle ul.wizard_steps li a { + height: 80px; } + +.wizard_verticle ul.wizard_steps li a:first-child { + margin-top: 20px; } + +.wizard_verticle ul.wizard_steps li a, .wizard_verticle ul.wizard_steps li:hover { + display: block; + position: relative; + -moz-opacity: 1; + filter: alpha(opacity=100); + opacity: 1; + color: #666; } + +.wizard_verticle ul.wizard_steps li a:before { + content: ""; + position: absolute; + height: 100%; + background: #ccc; + top: 20px; + width: 4px; + z-index: 4; + left: 49%; } + +.wizard_verticle ul.wizard_steps li a.disabled .step_no { + background: #ccc; } + +.wizard_verticle ul.wizard_steps li a .step_no { + width: 40px; + height: 40px; + line-height: 40px; + border-radius: 100px; + display: block; + margin: 0 auto 5px; + font-size: 16px; + text-align: center; + position: relative; + z-index: 5; } + +.wizard_verticle ul.wizard_steps li a.selected:before, .step_no { + background: #34495E; + color: #fff; } + +.wizard_verticle ul.wizard_steps li a.done:before, .wizard_verticle ul.wizard_steps li a.done .step_no { + background: #1ABB9C; + color: #fff; } + +.wizard_verticle ul.wizard_steps li:first-child a:before { + left: 49%; } + +.wizard_verticle ul.wizard_steps li:last-child a:before { + left: 49%; + left: auto; + width: 0; } + +.form_wizard .loader { + display: none; } + +.form_wizard .msgBox { + display: none; } + +/** jQuery Smart Wizard **/ +/** bootstrap-progressbar **/ +.progress { + border-radius: 0; } + +.progress-bar-info { + background-color: #3498DB; } + +.progress-bar-success { + background-color: #26B99A; } + +.progress_summary .progress { + margin: 5px 0 12px !important; } + +.progress_summary .row { + margin-bottom: 5px; } + +.progress_summary .row .col-xs-2 { + padding: 0; } + +.progress_summary .more_info span { + text-align: right; + float: right; } + +.progress_summary .data span { + text-align: right; + float: right; } + +.progress_summary p { + margin-bottom: 3px; + width: 100%; } + +.progress_title .left { + float: left; + text-align: left; } + +.progress_title .right { + float: right; + text-align: right; + font-weight: 300; } + +.progress.progress_sm { + border-radius: 0; + margin-bottom: 18px; + height: 10px !important; } + +.progress.progress_sm .progress-bar { + height: 10px !important; } + +.dashboard_graph p { + margin: 0 0 4px; } + +ul.verticle_bars { + width: 100%; } + +ul.verticle_bars li { + width: 23%; + height: 200px; + margin: 0; } + +.progress.vertical.progress_wide { + width: 35px; } + +/** bootstrap-progressbar **/ +/** PNotify **/ +.alert-success { + color: #ffffff; + background-color: rgba(38, 185, 154, 0.88); + border-color: rgba(38, 185, 154, 0.88); } + +.alert-info { + color: #E9EDEF; + background-color: rgba(52, 152, 219, 0.88); + border-color: rgba(52, 152, 219, 0.88); } + +.alert-warning { + color: #E9EDEF; + background-color: rgba(243, 156, 18, 0.88); + border-color: rgba(243, 156, 18, 0.88); } + +.alert-danger, +.alert-error { + color: #E9EDEF; + background-color: rgba(231, 76, 60, 0.88); + border-color: rgba(231, 76, 60, 0.88); } + +.ui-pnotify.dark .ui-pnotify-container { + color: #E9EDEF; + background-color: rgba(52, 73, 94, 0.88); + border-color: rgba(52, 73, 94, 0.88); } + +.custom-notifications { + position: fixed; + margin: 15px; + right: 0; + float: right; + width: 400px; + z-index: 4000; + bottom: 0; } + +ul.notifications { + float: right; + display: block; + margin-bottom: 7px; + padding: 0; + width: 100%; } + +.notifications li { + float: right; + margin: 3px; + width: 36px; + box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.3); } + +.notifications li:last-child { + margin-left: 0; } + +.notifications a { + display: block; + text-align: center; + text-decoration: none; + text-transform: uppercase; + padding: 9px 8px; } + +.tabbed_notifications .text { + padding: 5px 15px; + height: 140px; + border-radius: 7px; + box-shadow: 6px 6px 6px rgba(0, 0, 0, 0.3); } + +.tabbed_notifications div p { + display: inline-block; } + +.tabbed_notifications h2 { + font-weight: bold; + text-transform: uppercase; + width: 80%; + float: left; + height: 20px; + text-overflow: ellipsis; + overflow: hidden; + display: block; } + +.tabbed_notifications .close { + padding: 5px; + color: #E9EDEF; + float: right; + opacity: 1; } + +/** /PNotify **/ +/** FullCalendar **/ +.fc-state-default { + background: #f5f5f5; + color: #73879C; } + +.fc-state-down, +.fc-state-active { + color: #333; + background: #ccc; } + +/** /FullCalendar **/ +/** Dropzone.js **/ +.dropzone { + min-height: 300px; + border: 1px solid #e5e5e5; } + +/** /Dropzone.js **/ diff --git a/flask/app/static/js/jquery.sparkline.min.js b/flask/app/static/js/jquery.sparkline.min.js new file mode 100644 index 0000000..328f4b6 --- /dev/null +++ b/flask/app/static/js/jquery.sparkline.min.js @@ -0,0 +1,6 @@ +/* jquery.sparkline 2.1.3 - http://omnipotent.net/jquery.sparkline/ +** Licensed under the New BSD License - see above site for details */ + +(function(document,Math,undefined){(function(factory){if(typeof define==="function"&&define.amd){define(["jquery"],factory)}else if(jQuery&&!jQuery.fn.sparkline){factory(jQuery)}})(function($){"use strict";var UNSET_OPTION={},getDefaults,createClass,SPFormat,clipval,quartile,normalizeValue,normalizeValues,remove,isNumber,all,sum,addCSS,ensureArray,formatNumber,RangeMap,MouseHandler,Tooltip,barHighlightMixin,line,bar,tristate,discrete,bullet,pie,box,defaultStyles,initStyles,VShape,VCanvas_base,VCanvas_canvas,VCanvas_vml,pending,shapeCount=0;getDefaults=function(){return{common:{type:"line",lineColor:"#00f",fillColor:"#cdf",defaultPixelsPerValue:3,width:"auto",height:"auto",composite:false,tagValuesAttribute:"values",tagOptionsPrefix:"spark",enableTagOptions:false,enableHighlight:true,highlightLighten:1.4,tooltipSkipNull:true,tooltipPrefix:"",tooltipSuffix:"",disableHiddenCheck:false,numberFormatter:false,numberDigitGroupCount:3,numberDigitGroupSep:",",numberDecimalMark:".",disableTooltips:false,disableInteraction:false},line:{spotColor:"#f80",highlightSpotColor:"#5f5",highlightLineColor:"#f22",spotRadius:1.5,minSpotColor:"#f80",maxSpotColor:"#f80",lineWidth:1,normalRangeMin:undefined,normalRangeMax:undefined,normalRangeColor:"#ccc",drawNormalOnTop:false,chartRangeMin:undefined,chartRangeMax:undefined,chartRangeMinX:undefined,chartRangeMaxX:undefined,tooltipFormat:new SPFormat('● {{prefix}}{{y}}{{suffix}}')},bar:{barColor:"#3366cc",negBarColor:"#f44",stackedBarColor:["#3366cc","#dc3912","#ff9900","#109618","#66aa00","#dd4477","#0099c6","#990099"],zeroColor:undefined,nullColor:undefined,zeroAxis:true,barWidth:4,barSpacing:1,chartRangeMax:undefined,chartRangeMin:undefined,chartRangeClip:false,colorMap:undefined,tooltipFormat:new SPFormat('● {{prefix}}{{value}}{{suffix}}')},tristate:{barWidth:4,barSpacing:1,posBarColor:"#6f6",negBarColor:"#f44",zeroBarColor:"#999",colorMap:{},tooltipFormat:new SPFormat('● {{value:map}}'),tooltipValueLookups:{map:{"-1":"Loss",0:"Draw",1:"Win"}}},discrete:{lineHeight:"auto",thresholdColor:undefined,thresholdValue:0,chartRangeMax:undefined,chartRangeMin:undefined,chartRangeClip:false,tooltipFormat:new SPFormat("{{prefix}}{{value}}{{suffix}}")},bullet:{targetColor:"#f33",targetWidth:3,performanceColor:"#33f",rangeColors:["#d3dafe","#a8b6ff","#7f94ff"],base:undefined,tooltipFormat:new SPFormat("{{fieldkey:fields}} - {{value}}"),tooltipValueLookups:{fields:{r:"Range",p:"Performance",t:"Target"}}},pie:{offset:0,sliceColors:["#3366cc","#dc3912","#ff9900","#109618","#66aa00","#dd4477","#0099c6","#990099"],borderWidth:0,borderColor:"#000",tooltipFormat:new SPFormat('● {{value}} ({{percent.1}}%)')},box:{raw:false,boxLineColor:"#000",boxFillColor:"#cdf",whiskerColor:"#000",outlierLineColor:"#333",outlierFillColor:"#fff",medianColor:"#f00",showOutliers:true,outlierIQR:1.5,spotRadius:1.5,target:undefined,targetColor:"#4a2",chartRangeMax:undefined,chartRangeMin:undefined,tooltipFormat:new SPFormat("{{field:fields}}: {{value}}"),tooltipFormatFieldlistKey:"field",tooltipValueLookups:{fields:{lq:"Lower Quartile",med:"Median",uq:"Upper Quartile",lo:"Left Outlier",ro:"Right Outlier",lw:"Left Whisker",rw:"Right Whisker"}}}}};defaultStyles=".jqstooltip { "+"position: absolute;"+"width: auto !important;"+"height: auto !important;"+"left: 0px;"+"top: 0px;"+"visibility: hidden;"+"background: rgb(0, 0, 0) transparent;"+"background-color: rgba(0,0,0,0.6);"+"filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);"+'-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";'+"color: white;"+"font: 10px arial, san serif;"+"text-align: left;"+"white-space: nowrap;"+"padding: 5px;"+"border: 1px solid white;"+"box-sizing: content-box;"+"z-index: 10000;"+"}"+".jqsfield { "+"color: white;"+"font: 10px arial, san serif;"+"text-align: left;"+"}";createClass=function(){var Class,args;Class=function(){this.init.apply(this,arguments)};if(arguments.length>1){if(arguments[0]){Class.prototype=$.extend(new arguments[0],arguments[arguments.length-1]);Class._super=arguments[0].prototype}else{Class.prototype=arguments[arguments.length-1]}if(arguments.length>2){args=Array.prototype.slice.call(arguments,1,-1);args.unshift(Class.prototype);$.extend.apply($,args)}}else{Class.prototype=arguments[0]}Class.prototype.cls=Class;return Class};$.SPFormatClass=SPFormat=createClass({fre:/\{\{([\w.]+?)(:(.+?))?\}\}/g,precre:/(\w+)\.(\d+)/,init:function(format,fclass){this.format=format;this.fclass=fclass},render:function(fieldset,lookups,options){var self=this,fields=fieldset,match,token,lookupkey,fieldvalue,prec;return this.format.replace(this.fre,function(){var lookup;token=arguments[1];lookupkey=arguments[3];match=self.precre.exec(token);if(match){prec=match[2];token=match[1]}else{prec=false}fieldvalue=fields[token];if(fieldvalue===undefined){return""}if(lookupkey&&lookups&&lookups[lookupkey]){lookup=lookups[lookupkey];if(lookup.get){return lookups[lookupkey].get(fieldvalue)||fieldvalue}else{return lookups[lookupkey][fieldvalue]||fieldvalue}}if(isNumber(fieldvalue)){if(options.get("numberFormatter")){fieldvalue=options.get("numberFormatter")(fieldvalue)}else{fieldvalue=formatNumber(fieldvalue,prec,options.get("numberDigitGroupCount"),options.get("numberDigitGroupSep"),options.get("numberDecimalMark"))}}return fieldvalue})}});$.spformat=function(format,fclass){return new SPFormat(format,fclass)};clipval=function(val,min,max){if(valmax){return max}return val};quartile=function(values,q){var vl;if(q===2){vl=Math.floor(values.length/2);return values.length%2?values[vl]:(values[vl-1]+values[vl])/2}else{if(values.length%2){vl=(values.length*q+q)/4;return vl%1?(values[Math.floor(vl)]+values[Math.floor(vl)-1])/2:values[vl-1]}else{vl=(values.length*q+2)/4;return vl%1?(values[Math.floor(vl)]+values[Math.floor(vl)-1])/2:values[vl-1]}}};normalizeValue=function(val){var nf;switch(val){case"undefined":val=undefined;break;case"null":val=null;break;case"true":val=true;break;case"false":val=false;break;default:nf=parseFloat(val);if(val==nf){val=nf}}return val};normalizeValues=function(vals){var i,result=[];for(i=vals.length;i--;){result[i]=normalizeValue(vals[i])}return result};remove=function(vals,filter){var i,vl,result=[];for(i=0,vl=vals.length;i0;i-=groupsize){num.splice(i,0,groupsep)}return num.join("")};all=function(val,arr,ignoreNull){var i;for(i=arr.length;i--;){if(ignoreNull&&arr[i]===null)continue;if(arr[i]!==val){return false}}return true};sum=function(vals){var total=0,i;for(i=vals.length;i--;){total+=typeof vals[i]==="number"?vals[i]:0}return total};ensureArray=function(val){return $.isArray(val)?val:[val]};addCSS=function(css){var tag,iefail;if(document.createStyleSheet){try{document.createStyleSheet().cssText=css;return}catch(e){iefail=true}}tag=document.createElement("style");tag.type="text/css";document.getElementsByTagName("head")[0].appendChild(tag);if(iefail){document.styleSheets[document.styleSheets.length-1].cssText=css}else{tag[typeof document.body.style.WebkitAppearance=="string"?"innerText":"innerHTML"]=css}};$.fn.simpledraw=function(width,height,useExisting,interact){var target,mhandler;if(useExisting&&(target=this.data("_jqs_vcanvas"))){return target}if($.fn.sparkline.canvas===false){return false}else if($.fn.sparkline.canvas===undefined){var el=document.createElement("canvas");if(!!(el.getContext&&el.getContext("2d"))){$.fn.sparkline.canvas=function(width,height,target,interact){return new VCanvas_canvas(width,height,target,interact)}}else if(document.namespaces&&!document.namespaces.v){document.namespaces.add("v","urn:schemas-microsoft-com:vml","#default#VML");$.fn.sparkline.canvas=function(width,height,target,interact){return new VCanvas_vml(width,height,target)}}else{$.fn.sparkline.canvas=false;return false}}if(width===undefined){width=$(this).innerWidth()}if(height===undefined){height=$(this).innerHeight()}target=$.fn.sparkline.canvas(width,height,this,interact);mhandler=$(this).data("_jqs_mhandler");if(mhandler){mhandler.registerCanvas(target)}return target};$.fn.cleardraw=function(){var target=this.data("_jqs_vcanvas");if(target){target.reset()}};$.RangeMapClass=RangeMap=createClass({init:function(map){var key,range,rangelist=[];for(key in map){if(map.hasOwnProperty(key)&&typeof key==="string"&&key.indexOf(":")>-1){range=key.split(":");range[0]=range[0].length===0?-Infinity:parseFloat(range[0]);range[1]=range[1].length===0?Infinity:parseFloat(range[1]);range[2]=map[key];rangelist.push(range)}}this.map=map;this.rangelist=rangelist||false},get:function(value){var rangelist=this.rangelist,i,range,result;if((result=this.map[value])!==undefined){return result}if(rangelist){for(i=rangelist.length;i--;){range=rangelist[i];if(range[0]<=value&&range[1]>=value){return range[2]}}}return undefined}});$.range_map=function(map){return new RangeMap(map)};MouseHandler=createClass({init:function(el,options){var $el=$(el);this.$el=$el;this.options=options;this.currentPageX=0;this.currentPageY=0;this.el=el;this.splist=[];this.tooltip=null;this.over=false;this.displayTooltips=!options.get("disableTooltips");this.highlightEnabled=!options.get("disableHighlight")},registerSparkline:function(sp){this.splist.push(sp);if(this.over){this.updateDisplay()}},registerCanvas:function(canvas){var $canvas=$(canvas.canvas);this.canvas=canvas;this.$canvas=$canvas;$canvas.mouseenter($.proxy(this.mouseenter,this));$canvas.mouseleave($.proxy(this.mouseleave,this));$canvas.click($.proxy(this.mouseclick,this))},reset:function(removeTooltip){this.splist=[];if(this.tooltip&&removeTooltip){this.tooltip.remove();this.tooltip=undefined}},mouseclick:function(e){var clickEvent=$.Event("sparklineClick");clickEvent.originalEvent=e;clickEvent.sparklines=this.splist;this.$el.trigger(clickEvent)},mouseenter:function(e){$(document.body).unbind("mousemove.jqs");$(document.body).bind("mousemove.jqs",$.proxy(this.mousemove,this));this.over=true;this.currentPageX=e.pageX;this.currentPageY=e.pageY;this.currentEl=e.target;if(!this.tooltip&&this.displayTooltips){this.tooltip=new Tooltip(this.options);this.tooltip.updatePosition(e.pageX,e.pageY)}this.updateDisplay()},mouseleave:function(){$(document.body).unbind("mousemove.jqs");var splist=this.splist,spcount=splist.length,needsRefresh=false,sp,i;this.over=false;this.currentEl=null;if(this.tooltip){this.tooltip.remove();this.tooltip=null}for(i=0;i",{id:"jqssizetip",style:sizetipStyle,"class":tooltipClassname});this.tooltip=$("

",{id:"jqstooltip","class":tooltipClassname}).appendTo(this.container);offset=this.tooltip.offset();this.offsetLeft=offset.left;this.offsetTop=offset.top;this.hidden=true;$(window).unbind("resize.jqs scroll.jqs");$(window).bind("resize.jqs scroll.jqs",$.proxy(this.updateWindowDims,this));this.updateWindowDims()},updateWindowDims:function(){this.scrollTop=$(window).scrollTop();this.scrollLeft=$(window).scrollLeft();this.scrollRight=this.scrollLeft+$(window).width();this.updatePosition()},getSize:function(content){this.sizetip.html(content).appendTo(this.container);this.width=this.sizetip.width()+1;this.height=this.sizetip.height();this.sizetip.remove()},setContent:function(content){if(!content){this.tooltip.css("visibility","hidden");this.hidden=true;return}this.getSize(content);this.tooltip.html(content).css({width:this.width,height:this.height,visibility:"visible"});if(this.hidden){this.hidden=false;this.updatePosition()}},updatePosition:function(x,y){if(x===undefined){if(this.mousex===undefined){return}x=this.mousex-this.offsetLeft;y=this.mousey-this.offsetTop}else{this.mousex=x=x-this.offsetLeft;this.mousey=y=y-this.offsetTop}if(!this.height||!this.width||this.hidden){return}y-=this.height+this.tooltipOffsetY;x+=this.tooltipOffsetX;if(ythis.scrollRight){x=this.scrollRight-this.width}this.tooltip.css({left:x,top:y})},remove:function(){this.tooltip.remove();this.sizetip.remove();this.sizetip=this.tooltip=undefined;$(window).unbind("resize.jqs scroll.jqs")}});initStyles=function(){addCSS(defaultStyles)};$(initStyles);pending=[];$.fn.sparkline=function(userValues,userOptions){return this.each(function(){var options=new $.fn.sparkline.options(this,userOptions),$this=$(this),render,i;render=function(){var values,width,height,tmp,mhandler,sp,vals;if(userValues==="html"||userValues===undefined){vals=this.getAttribute(options.get("tagValuesAttribute"));if(vals===undefined||vals===null){vals=$this.html()}values=vals.replace(/(^\s*\s*$)|\s+/g,"").split(",")}else{values=userValues}width=options.get("width")==="auto"?values.length*options.get("defaultPixelsPerValue"):options.get("width");if(options.get("height")==="auto"){if(!options.get("composite")||!$.data(this,"_jqs_vcanvas")){tmp=document.createElement("span");tmp.innerHTML="a";$this.html(tmp);height=$(tmp).innerHeight()||$(tmp).height();$(tmp).remove();tmp=null}}else{height=options.get("height")}if(!options.get("disableInteraction")){mhandler=$.data(this,"_jqs_mhandler");if(!mhandler){mhandler=new MouseHandler(this,options);$.data(this,"_jqs_mhandler",mhandler)}else if(!options.get("composite")){mhandler.reset()}}else{mhandler=false}if(options.get("composite")&&!$.data(this,"_jqs_vcanvas")){if(!$.data(this,"_jqs_errnotify")){alert("Attempted to attach a composite sparkline to an element with no existing sparkline");$.data(this,"_jqs_errnotify",true)}return}sp=new($.fn.sparkline[options.get("type")])(this,values,options,width,height);sp.render();if(mhandler){mhandler.registerSparkline(sp)}};if($(this).html()&&!options.get("disableHiddenCheck")&&$(this).is(":hidden")||!$(this).parents("body").length){if(!options.get("composite")&&$.data(this,"_jqs_pending")){for(i=pending.length;i;i--){if(pending[i-1][0]==this){pending.splice(i-1,1)}}}pending.push([this,render]);$.data(this,"_jqs_pending",true)}else{render.call(this)}})};$.fn.sparkline.defaults=getDefaults();$.sparkline_display_visible=function(){var el,i,pl;var done=[];for(i=0,pl=pending.length;ithis.canvasWidth||y>this.canvasHeight||x<0||y<0){return null}newRegion=this.getRegion(el,x,y);if(currentRegion!==newRegion){if(currentRegion!==undefined&&highlightEnabled){this.removeHighlight()}this.currentRegion=newRegion;if(newRegion!==undefined&&highlightEnabled){this.renderHighlight()}return true}return false},clearRegionHighlight:function(){if(this.currentRegion!==undefined){this.removeHighlight();this.currentRegion=undefined;return true}return false},renderHighlight:function(){this.changeHighlight(true)},removeHighlight:function(){this.changeHighlight(false)},changeHighlight:function(highlight){},getCurrentRegionTooltip:function(){var options=this.options,header="",entries=[],fields,formats,formatlen,fclass,text,i,showFields,showFieldsKey,newFields,fv,formatter,format,fieldlen,j;if(this.currentRegion===undefined){return""}fields=this.getCurrentRegionFields();formatter=options.get("tooltipFormatter");if(formatter){return formatter(this,options,fields)}if(options.get("tooltipChartTitle")){header+='
'+options.get("tooltipChartTitle")+"
\n"}formats=this.options.get("tooltipFormat");if(!formats){return""}if(!$.isArray(formats)){formats=[formats]}if(!$.isArray(fields)){fields=[fields]}showFields=this.options.get("tooltipFormatFieldlist");showFieldsKey=this.options.get("tooltipFormatFieldlistKey");if(showFields&&showFieldsKey){newFields=[];for(i=fields.length;i--;){fv=fields[i][showFieldsKey];if((j=$.inArray(fv,showFields))!=-1){newFields[j]=fields[i]}}fields=newFields}formatlen=formats.length;fieldlen=fields.length;for(i=0;i'+text+"
")}}}if(entries.length){return header+entries.join("\n")}return""},getCurrentRegionFields:function(){},calcHighlightColor:function(color,options){var highlightColor=options.get("highlightColor"),lighten=options.get("highlightLighten"),parse,mult,rgbnew,i;if(highlightColor){return highlightColor}if(lighten){parse=/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color)||/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);if(parse){rgbnew=[];mult=color.length===4?16:1;for(i=0;i<3;i++){rgbnew[i]=clipval(Math.round(parseInt(parse[i+1],16)*mult*lighten),0,255)}return"rgb("+rgbnew.join(",")+")"}}return color}});barHighlightMixin={changeHighlight:function(highlight){var currentRegion=this.currentRegion,target=this.target,shapeids=this.regionShapes[currentRegion],newShapes;if(shapeids){newShapes=this.renderRegion(currentRegion,highlight);if($.isArray(newShapes)||$.isArray(shapeids)){target.replaceWithShapes(shapeids,newShapes);this.regionShapes[currentRegion]=$.map(newShapes,function(newShape){return newShape.id})}else{target.replaceWithShape(shapeids,newShapes);this.regionShapes[currentRegion]=newShapes.id}}},render:function(){var values=this.values,target=this.target,regionShapes=this.regionShapes,shapes,ids,i,j;if(!this.cls._super.render.call(this)){return}for(i=values.length;i--;){shapes=this.renderRegion(i);if(shapes){if($.isArray(shapes)){ids=[];for(j=shapes.length;j--;){shapes[j].append();ids.push(shapes[j].id)}regionShapes[i]=ids}else{shapes.append();regionShapes[i]=shapes.id}}else{regionShapes[i]=null}}target.render()}};$.fn.sparkline.line=line=createClass($.fn.sparkline._base,{type:"line",init:function(el,values,options,width,height){line._super.init.call(this,el,values,options,width,height);this.vertices=[];this.regionMap=[];this.xvalues=[];this.yvalues=[];this.yminmax=[];this.hightlightSpotId=null;this.lastShapeId=null;this.initTarget()},getRegion:function(el,x,y){var i,regionMap=this.regionMap;for(i=regionMap.length;i--;){if(regionMap[i]!==null&&x>=regionMap[i][0]&&x<=regionMap[i][1]){return regionMap[i][2]}}return undefined},getCurrentRegionFields:function(){var currentRegion=this.currentRegion;return{isNull:this.yvalues[currentRegion]===null,x:this.xvalues[currentRegion],y:this.yvalues[currentRegion],color:this.options.get("lineColor"),fillColor:this.options.get("fillColor"),offset:currentRegion}},renderHighlight:function(){var currentRegion=this.currentRegion,target=this.target,vertex=this.vertices[currentRegion],options=this.options,spotRadius=options.get("spotRadius"),highlightSpotColor=options.get("highlightSpotColor"),highlightLineColor=options.get("highlightLineColor"),highlightSpot,highlightLine;if(!vertex){return}if(spotRadius&&highlightSpotColor){highlightSpot=target.drawCircle(vertex[0],vertex[1],spotRadius,undefined,highlightSpotColor);this.highlightSpotId=highlightSpot.id;target.insertAfterShape(this.lastShapeId,highlightSpot)}if(highlightLineColor){highlightLine=target.drawLine(vertex[0],this.canvasTop,vertex[0],this.canvasTop+this.canvasHeight,highlightLineColor);this.highlightLineId=highlightLine.id;target.insertAfterShape(this.lastShapeId,highlightLine)}},removeHighlight:function(){var target=this.target;if(this.highlightSpotId){target.removeShapeId(this.highlightSpotId);this.highlightSpotId=null}if(this.highlightLineId){target.removeShapeId(this.highlightLineId);this.highlightLineId=null}},scanValues:function(){var values=this.values,valcount=values.length,xvalues=this.xvalues,yvalues=this.yvalues,yminmax=this.yminmax,i,val,isStr,isArray,sp;for(i=0;ithis.maxy){this.maxy=normalRangeMax}}if(options.get("chartRangeMin")!==undefined&&(options.get("chartRangeClip")||options.get("chartRangeMin")this.maxy)){this.maxy=options.get("chartRangeMax")}if(options.get("chartRangeMinX")!==undefined&&(options.get("chartRangeClipX")||options.get("chartRangeMinX")this.maxx)){this.maxx=options.get("chartRangeMaxX")}},drawNormalRange:function(canvasLeft,canvasTop,canvasHeight,canvasWidth,rangey){var normalRangeMin=this.options.get("normalRangeMin"),normalRangeMax=this.options.get("normalRangeMax"),ytop=canvasTop+Math.round(canvasHeight-canvasHeight*((normalRangeMax-this.miny)/rangey)),height=Math.round(canvasHeight*(normalRangeMax-normalRangeMin)/rangey);this.target.drawRect(canvasLeft,ytop,canvasWidth,height,undefined,this.options.get("normalRangeColor")).append()},render:function(){var options=this.options,target=this.target,canvasWidth=this.canvasWidth,canvasHeight=this.canvasHeight,vertices=this.vertices,spotRadius=options.get("spotRadius"),regionMap=this.regionMap,rangex,rangey,yvallast,canvasTop,canvasLeft,vertex,path,paths,x,y,xnext,xpos,xposnext,last,next,yvalcount,lineShapes,fillShapes,plen,valueSpots,hlSpotsEnabled,color,xvalues,yvalues,i;if(!line._super.render.call(this)){return}this.scanValues();this.processRangeOptions();xvalues=this.xvalues;yvalues=this.yvalues;if(!this.yminmax.length||this.yvalues.length<2){return}canvasTop=canvasLeft=0;rangex=this.maxx-this.minx===0?1:this.maxx-this.minx;rangey=this.maxy-this.miny===0?1:this.maxy-this.miny;yvallast=this.yvalues.length-1;if(spotRadius&&(canvasWidththis.maxy){y=this.maxy}if(!path.length){path.push([xpos,canvasTop+canvasHeight])}vertex=[xpos,canvasTop+Math.round(canvasHeight-canvasHeight*((y-this.miny)/rangey))];path.push(vertex);vertices.push(vertex)}}lineShapes=[];fillShapes=[];plen=paths.length;for(i=0;i2){path[0]=[path[0][0],path[1][1]]}lineShapes.push(path)}}plen=fillShapes.length;for(i=0;i-1;if(isStackString||$.isArray(val)){stacked=true;if(isStackString){val=values[i]=normalizeValues(val.split(":")); + +}val=remove(val,null);groupMin=Math.min.apply(Math,val);groupMax=Math.max.apply(Math,val);if(groupMinstackMax){stackMax=groupMax}}}this.stacked=stacked;this.regionShapes={};this.barWidth=barWidth;this.barSpacing=barSpacing;this.totalBarWidth=barWidth+barSpacing;this.width=width=values.length*barWidth+(values.length-1)*barSpacing;this.initTarget();if(chartRangeClip){clipMin=chartRangeMin===undefined?-Infinity:chartRangeMin;clipMax=chartRangeMax===undefined?Infinity:chartRangeMax}numValues=[];stackRanges=stacked?[]:numValues;var stackTotals=[];var stackRangesNeg=[];for(i=0,vlen=values.length;i0){stackTotals[i]+=val}if(stackMin<0&&stackMax>0){if(val<0){stackRangesNeg[i]+=Math.abs(val)}else{stackRanges[i]+=val}}else{stackRanges[i]+=Math.abs(val-(val<0?stackMax:stackMin))}numValues.push(val)}}}else{val=chartRangeClip?clipval(values[i],clipMin,clipMax):values[i];val=values[i]=normalizeValue(val);if(val!==null){numValues.push(val)}}}this.max=max=Math.max.apply(Math,numValues);this.min=min=Math.min.apply(Math,numValues);this.stackMax=stackMax=stacked?Math.max.apply(Math,stackTotals):max;this.stackMin=stackMin=stacked?Math.min.apply(Math,numValues):min;if(options.get("chartRangeMin")!==undefined&&(options.get("chartRangeClip")||options.get("chartRangeMin")max)){max=options.get("chartRangeMax")}this.zeroAxis=zeroAxis=options.get("zeroAxis",true);if(min<=0&&max>=0&&zeroAxis){xaxisOffset=0}else if(zeroAxis==false){xaxisOffset=min}else if(min>0){xaxisOffset=min}else{xaxisOffset=max}this.xaxisOffset=xaxisOffset;range=stacked?Math.max.apply(Math,stackRanges)+Math.max.apply(Math,stackRangesNeg):max-min;this.canvasHeightEf=zeroAxis&&min<0?this.canvasHeight-2:this.canvasHeight-1;if(min=0?stackMax:max;yoffset=(yMaxCalc-xaxisOffset)/range*this.canvasHeight;if(yoffset!==Math.ceil(yoffset)){this.canvasHeightEf-=2;yoffset=Math.ceil(yoffset)}}else{yoffset=this.canvasHeight}this.yoffset=yoffset;if($.isArray(options.get("colorMap"))){this.colorMapByIndex=options.get("colorMap");this.colorMapByValue=null}else{this.colorMapByIndex=null;this.colorMapByValue=options.get("colorMap");if(this.colorMapByValue&&this.colorMapByValue.get===undefined){this.colorMapByValue=new RangeMap(this.colorMapByValue)}}this.range=range},getRegion:function(el,x,y){var result=Math.floor(x/this.totalBarWidth);return result<0||result>=this.values.length?undefined:result},getCurrentRegionFields:function(){var currentRegion=this.currentRegion,values=ensureArray(this.values[currentRegion]),result=[],value,i;for(i=values.length;i--;){value=values[i];result.push({isNull:value===null,value:value,color:this.calcColor(i,value,currentRegion),offset:currentRegion})}return result},calcColor:function(stacknum,value,valuenum){var colorMapByIndex=this.colorMapByIndex,colorMapByValue=this.colorMapByValue,options=this.options,color,newColor;if(this.stacked){color=options.get("stackedBarColor")}else{color=value<0?options.get("negBarColor"):options.get("barColor")}if(value===0&&options.get("zeroColor")!==undefined){color=options.get("zeroColor")}if(colorMapByValue&&(newColor=colorMapByValue.get(value))){color=newColor}else if(colorMapByIndex&&colorMapByIndex.length>valuenum){color=colorMapByIndex[valuenum]}return $.isArray(color)?color[stacknum%color.length]:color},renderRegion:function(valuenum,highlight){var vals=this.values[valuenum],options=this.options,xaxisOffset=this.xaxisOffset,result=[],range=this.range,stacked=this.stacked,target=this.target,x=valuenum*this.totalBarWidth,canvasHeightEf=this.canvasHeightEf,yoffset=this.yoffset,y,height,color,isNull,yoffsetNeg,i,valcount,val,minPlotted,allMin;vals=$.isArray(vals)?vals:[vals];valcount=vals.length;val=vals[0];isNull=all(null,vals);allMin=all(xaxisOffset,vals,true);if(isNull){if(options.get("nullColor")){color=highlight?options.get("nullColor"):this.calcHighlightColor(options.get("nullColor"),options);y=yoffset>0?yoffset-1:yoffset;return target.drawRect(x,y,this.barWidth-1,0,color,color)}else{return undefined}}yoffsetNeg=yoffset;for(i=0;i0){height=Math.floor(canvasHeightEf*(Math.abs(val-xaxisOffset)/range))+1}else{height=1}if(valvaluenum){color=colorMapByIndex[valuenum]}else if(values[valuenum]<0){color=options.get("negBarColor")}else if(values[valuenum]>0){color=options.get("posBarColor")}else{color=options.get("zeroBarColor")}return color},renderRegion:function(valuenum,highlight){var values=this.values,options=this.options,target=this.target,canvasHeight,height,halfHeight,x,y,color;canvasHeight=target.pixelHeight;halfHeight=Math.round(canvasHeight/2);x=valuenum*this.totalBarWidth;if(values[valuenum]<0){y=halfHeight;height=halfHeight-1}else if(values[valuenum]>0){y=0;height=halfHeight-1}else{y=halfHeight-1;height=2}color=this.calcColor(values[valuenum],valuenum);if(color===null){return}if(highlight){color=this.calcHighlightColor(color,options)}return target.drawRect(x,y,this.barWidth-1,height-1,color,color)}});$.fn.sparkline.discrete=discrete=createClass($.fn.sparkline._base,barHighlightMixin,{type:"discrete",init:function(el,values,options,width,height){discrete._super.init.call(this,el,values,options,width,height);this.regionShapes={};this.values=values=$.map(values,Number);this.min=Math.min.apply(Math,values);this.max=Math.max.apply(Math,values);this.range=this.max-this.min;this.width=width=options.get("width")==="auto"?values.length*2:this.width;this.interval=Math.floor(width/values.length);this.itemWidth=width/values.length;if(options.get("chartRangeMin")!==undefined&&(options.get("chartRangeClip")||options.get("chartRangeMin")this.max)){this.max=options.get("chartRangeMax")}this.initTarget();if(this.target){this.lineHeight=options.get("lineHeight")==="auto"?Math.round(this.canvasHeight*.3):options.get("lineHeight")}},getRegion:function(el,x,y){return Math.floor(x/this.itemWidth)},getCurrentRegionFields:function(){var currentRegion=this.currentRegion;return{isNull:this.values[currentRegion]===undefined,value:this.values[currentRegion],offset:currentRegion}},renderRegion:function(valuenum,highlight){var values=this.values,options=this.options,min=this.min,max=this.max,range=this.range,interval=this.interval,target=this.target,canvasHeight=this.canvasHeight,lineHeight=this.lineHeight,pheight=canvasHeight-lineHeight,ytop,val,color,x;val=clipval(values[valuenum],min,max);x=valuenum*interval;ytop=Math.round(pheight-pheight*((val-min)/range));color=options.get("thresholdColor")&&val0){for(i=values.length;i--;){total+=values[i]}}this.total=total;this.initTarget();this.radius=Math.floor(Math.min(this.canvasWidth,this.canvasHeight)/2)},getRegion:function(el,x,y){var shapeid=this.target.getShapeAt(el,x,y);return shapeid!==undefined&&this.shapes[shapeid]!==undefined?this.shapes[shapeid]:undefined},getCurrentRegionFields:function(){var currentRegion=this.currentRegion;return{isNull:this.values[currentRegion]===undefined,value:this.values[currentRegion],percent:this.values[currentRegion]/this.total*100,color:this.options.get("sliceColors")[currentRegion%this.options.get("sliceColors").length],offset:currentRegion}},changeHighlight:function(highlight){var currentRegion=this.currentRegion,newslice=this.renderSlice(currentRegion,highlight),shapeid=this.valueShapes[currentRegion];delete this.shapes[shapeid];this.target.replaceWithShape(shapeid,newslice);this.valueShapes[currentRegion]=newslice.id;this.shapes[newslice.id]=currentRegion},renderSlice:function(valuenum,highlight){var target=this.target,options=this.options,radius=this.radius,borderWidth=options.get("borderWidth"),offset=options.get("offset"),circle=2*Math.PI,values=this.values,total=this.total,next=offset?2*Math.PI*(offset/360):0,start,end,i,vlen,color;vlen=values.length;for(i=0;i0){end=next+circle*(values[i]/total)}if(valuenum===i){color=options.get("sliceColors")[i%options.get("sliceColors").length];if(highlight){color=this.calcHighlightColor(color,options)}return target.drawPieSlice(radius,radius,radius-borderWidth,start,end,undefined,color)}next=end}},render:function(){var target=this.target,values=this.values,options=this.options,radius=this.radius,borderWidth=options.get("borderWidth"),shape,i;if(!pie._super.render.call(this)){return}if(borderWidth){target.drawCircle(radius,radius,Math.floor(radius-borderWidth/2),options.get("borderColor"),undefined,borderWidth).append()}for(i=values.length;i--;){if(values[i]){shape=this.renderSlice(i).append();this.valueShapes[i]=shape.id;this.shapes[shape.id]=i}}target.render()}});$.fn.sparkline.box=box=createClass($.fn.sparkline._base,{type:"box",init:function(el,values,options,width,height){box._super.init.call(this,el,values,options,width,height);this.values=$.map(values,Number);this.width=options.get("width")==="auto"?"4.0em":width;this.initTarget();if(!this.values.length){this.disabled=1}},getRegion:function(){return 1},getCurrentRegionFields:function(){var result=[{field:"lq",value:this.quartiles[0]},{field:"med",value:this.quartiles[1]},{field:"uq",value:this.quartiles[2]}];if(this.loutlier!==undefined){result.push({field:"lo",value:this.loutlier})}if(this.routlier!==undefined){result.push({field:"ro",value:this.routlier})}if(this.lwhisker!==undefined){result.push({field:"lw",value:this.lwhisker})}if(this.rwhisker!==undefined){result.push({field:"rw",value:this.rwhisker})}return result},render:function(){var target=this.target,values=this.values,vlen=values.length,options=this.options,canvasWidth=this.canvasWidth,canvasHeight=this.canvasHeight,minValue=options.get("chartRangeMin")===undefined?Math.min.apply(Math,values):options.get("chartRangeMin"),maxValue=options.get("chartRangeMax")===undefined?Math.max.apply(Math,values):options.get("chartRangeMax"),canvasLeft=0,lwhisker,loutlier,iqr,q1,q2,q3,rwhisker,routlier,i,size,unitSize;if(!box._super.render.call(this)){return}if(options.get("raw")){if(options.get("showOutliers")&&values.length>5){loutlier=values[0];lwhisker=values[1];q1=values[2];q2=values[3];q3=values[4];rwhisker=values[5];routlier=values[6]}else{lwhisker=values[0];q1=values[1];q2=values[2];q3=values[3];rwhisker=values[4]}}else{values.sort(function(a,b){return a-b});q1=quartile(values,1);q2=quartile(values,2);q3=quartile(values,3);iqr=q3-q1;if(options.get("showOutliers")){lwhisker=rwhisker=undefined;for(i=0;iq1-iqr*options.get("outlierIQR")){lwhisker=values[i]}if(values[i]rwhisker){target.drawCircle((routlier-minValue)*unitSize+canvasLeft,canvasHeight/2,options.get("spotRadius"),options.get("outlierLineColor"),options.get("outlierFillColor")).append()}}target.drawRect(Math.round((q1-minValue)*unitSize+canvasLeft),Math.round(canvasHeight*.1),Math.round((q3-q1)*unitSize),Math.round(canvasHeight*.8),options.get("boxLineColor"),options.get("boxFillColor")).append();target.drawLine(Math.round((lwhisker-minValue)*unitSize+canvasLeft),Math.round(canvasHeight/2),Math.round((q1-minValue)*unitSize+canvasLeft),Math.round(canvasHeight/2),options.get("lineColor")).append();target.drawLine(Math.round((lwhisker-minValue)*unitSize+canvasLeft),Math.round(canvasHeight/4),Math.round((lwhisker-minValue)*unitSize+canvasLeft),Math.round(canvasHeight-canvasHeight/4),options.get("whiskerColor")).append();target.drawLine(Math.round((rwhisker-minValue)*unitSize+canvasLeft),Math.round(canvasHeight/2),Math.round((q3-minValue)*unitSize+canvasLeft),Math.round(canvasHeight/2),options.get("lineColor")).append();target.drawLine(Math.round((rwhisker-minValue)*unitSize+canvasLeft),Math.round(canvasHeight/4),Math.round((rwhisker-minValue)*unitSize+canvasLeft),Math.round(canvasHeight-canvasHeight/4),options.get("whiskerColor")).append();target.drawLine(Math.round((q2-minValue)*unitSize+canvasLeft),Math.round(canvasHeight*.1),Math.round((q2-minValue)*unitSize+canvasLeft),Math.round(canvasHeight*.9),options.get("medianColor")).append();if(options.get("target")){size=Math.ceil(options.get("spotRadius"));target.drawLine(Math.round((options.get("target")-minValue)*unitSize+canvasLeft),Math.round(canvasHeight/2-size),Math.round((options.get("target")-minValue)*unitSize+canvasLeft),Math.round(canvasHeight/2+size),options.get("targetColor")).append();target.drawLine(Math.round((options.get("target")-minValue)*unitSize+canvasLeft-size),Math.round(canvasHeight/2),Math.round((options.get("target")-minValue)*unitSize+canvasLeft+size),Math.round(canvasHeight/2),options.get("targetColor")).append()}target.render()}});VShape=createClass({init:function(target,id,type,args){this.target=target;this.id=id;this.type=type;this.args=args},append:function(){this.target.appendShape(this);return this}});VCanvas_base=createClass({_pxregex:/(\d+)(px)?\s*$/i,init:function(width,height,target){if(!width){return}this.width=width;this.height=height;this.target=target;this.lastShapeId=null;if(target[0]){target=target[0]}$.data(target,"_jqs_vcanvas",this)},drawLine:function(x1,y1,x2,y2,lineColor,lineWidth){return this.drawShape([[x1,y1],[x2,y2]],lineColor,lineWidth)},drawShape:function(path,lineColor,fillColor,lineWidth){return this._genShape("Shape",[path,lineColor,fillColor,lineWidth])},drawCircle:function(x,y,radius,lineColor,fillColor,lineWidth){return this._genShape("Circle",[x,y,radius,lineColor,fillColor,lineWidth])},drawPieSlice:function(x,y,radius,startAngle,endAngle,lineColor,fillColor){return this._genShape("PieSlice",[x,y,radius,startAngle,endAngle,lineColor,fillColor])},drawRect:function(x,y,width,height,lineColor,fillColor){return this._genShape("Rect",[x,y,width,height,lineColor,fillColor])},getElement:function(){return this.canvas},getLastShapeId:function(){return this.lastShapeId},reset:function(){alert("reset not implemented")},_insert:function(el,target){$(target).html(el)},_calculatePixelDims:function(width,height,canvas){var match;match=this._pxregex.exec(height);if(match){this.pixelHeight=match[1]}else{this.pixelHeight=$(canvas).height()}match=this._pxregex.exec(width);if(match){this.pixelWidth=match[1]}else{this.pixelWidth=$(canvas).width()}},_genShape:function(shapetype,shapeargs){var id=shapeCount++;shapeargs.unshift(id);return new VShape(this,id,shapetype,shapeargs)},appendShape:function(shape){alert("appendShape not implemented")},replaceWithShape:function(shapeid,shape){alert("replaceWithShape not implemented")},insertAfterShape:function(shapeid,shape){alert("insertAfterShape not implemented")},removeShapeId:function(shapeid){alert("removeShapeId not implemented")},getShapeAt:function(el,x,y){alert("getShapeAt not implemented")},render:function(){alert("render not implemented")}});VCanvas_canvas=createClass(VCanvas_base,{init:function(width,height,target,interact){VCanvas_canvas._super.init.call(this,width,height,target);this.canvas=document.createElement("canvas");if(target[0]){target=target[0]}$.data(target,"_jqs_vcanvas",this);$(this.canvas).css({display:"inline-block",width:width,height:height,verticalAlign:"top"});this._insert(this.canvas,target);this._calculatePixelDims(width,height,this.canvas);this.canvas.width=this.pixelWidth;this.canvas.height=this.pixelHeight;this.interact=interact;this.shapes={};this.shapeseq=[];this.currentTargetShapeId=undefined;$(this.canvas).css({width:this.pixelWidth,height:this.pixelHeight})},_getContext:function(lineColor,fillColor,lineWidth){var context=this.canvas.getContext("2d");if(lineColor!==undefined){context.strokeStyle=lineColor}context.lineWidth=lineWidth===undefined?1:lineWidth;if(fillColor!==undefined){context.fillStyle=fillColor}return context},reset:function(){var context=this._getContext();context.clearRect(0,0,this.pixelWidth,this.pixelHeight);this.shapes={};this.shapeseq=[];this.currentTargetShapeId=undefined},_drawShape:function(shapeid,path,lineColor,fillColor,lineWidth){var context=this._getContext(lineColor,fillColor,lineWidth),i,plen;context.beginPath();context.moveTo(path[0][0]+.5,path[0][1]+.5);for(i=1,plen=path.length;i';this.canvas.insertAdjacentHTML("beforeEnd",groupel);this.group=$(this.canvas).children()[0];this.rendered=false;this.prerender=""},_drawShape:function(shapeid,path,lineColor,fillColor,lineWidth){var vpath=[],initial,stroke,fill,closed,vel,plen,i;for(i=0,plen=path.length;i'+" ";return vel},_drawCircle:function(shapeid,x,y,radius,lineColor,fillColor,lineWidth){var stroke,fill,vel;x-=radius;y-=radius;stroke=lineColor===undefined?' stroked="false" ':' strokeWeight="'+lineWidth+'px" strokeColor="'+lineColor+'" ';fill=fillColor===undefined?' filled="false"':' fillColor="'+fillColor+'" filled="true" ';vel="';return vel},_drawPieSlice:function(shapeid,x,y,radius,startAngle,endAngle,lineColor,fillColor){var vpath,startx,starty,endx,endy,stroke,fill,vel;if(startAngle===endAngle){return""}if(endAngle-startAngle===2*Math.PI){startAngle=0;endAngle=2*Math.PI}startx=x+Math.round(Math.cos(startAngle)*radius);starty=y+Math.round(Math.sin(startAngle)*radius);endx=x+Math.round(Math.cos(endAngle)*radius);endy=y+Math.round(Math.sin(endAngle)*radius);if(startx===endx&&starty===endy){if(endAngle-startAngle'+" ";return vel},_drawRect:function(shapeid,x,y,width,height,lineColor,fillColor){return this._drawShape(shapeid,[[x,y],[x,y+height],[x+width,y+height],[x+width,y],[x,y]],lineColor,fillColor)},reset:function(){this.group.innerHTML=""},appendShape:function(shape){var vel=this["_draw"+shape.type].apply(this,shape.args);if(this.rendered){this.group.insertAdjacentHTML("beforeEnd",vel)}else{this.prerender+=vel}this.lastShapeId=shape.id;return shape.id},replaceWithShape:function(shapeid,shape){var existing=$("#jqsshape"+shapeid),vel=this["_draw"+shape.type].apply(this,shape.args);existing[0].outerHTML=vel},replaceWithShapes:function(shapeids,shapes){var existing=$("#jqsshape"+shapeids[0]),replace="",slen=shapes.length,i;for(i=0;i + + + + + + + + + BGP Dashboard + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flask/app/uwsgi.ini b/flask/app/uwsgi.ini new file mode 100644 index 0000000..7cdd459 --- /dev/null +++ b/flask/app/uwsgi.ini @@ -0,0 +1,16 @@ +[uwsgi] +#application's base folder +base = /var/www/app +#python module to import +module = bgp +#the variable that holds a flask application inside the module imported at line #6 +callable = app +#socket file's location +socket = /var/www/app/uwsgi.sock +#permissions for the socket file +chmod-socket = 666 +#Log directory +logto = /var/log/uwsgi/app/app.log +enable-threads = true + +chdir = /var/www/app diff --git a/flask/nginx/flask.conf b/flask/nginx/flask.conf new file mode 100644 index 0000000..8cca391 --- /dev/null +++ b/flask/nginx/flask.conf @@ -0,0 +1,18 @@ + +server { + listen 80; + server_name localhost; + charset utf-8; + client_max_body_size 75M; + + + location / { + include uwsgi_params; + uwsgi_pass unix:/var/www/app/uwsgi.sock; + } + + location /static { + root /var/www/app/; + } +} + diff --git a/flask/supervisor/supervisord.conf b/flask/supervisor/supervisord.conf new file mode 100644 index 0000000..cec81ef --- /dev/null +++ b/flask/supervisor/supervisord.conf @@ -0,0 +1,8 @@ +[supervisord] +nodaemon = true + +[program:nginx] +command = /usr/sbin/nginx + +[program:uwsgi] +command = /venv/bin/uwsgi --ini /var/www/app/uwsgi.ini diff --git a/gobgp/Dockerfile b/gobgp/Dockerfile new file mode 100755 index 0000000..08fd352 --- /dev/null +++ b/gobgp/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:24.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get remove -y binutils && \ + apt-get install -y \ + python3 \ + python3-pip \ + python3-venv \ + wget && \ + rm -rf /var/lib/apt/lists/* +COPY ./requirements.txt /tmp/requirements.txt +RUN python3 -m venv venv && chmod +x venv +RUN . venv/bin/activate && pip3 install -r /tmp/requirements.txt +RUN wget https://github.com/osrg/gobgp/releases/download/v3.27.0/gobgp_3.27.0_linux_amd64.tar.gz && \ + tar -xzvf gobgp_3.27.0_linux_amd64.tar.gz && \ + mv gobgp /usr/local/bin/gobgp && \ + mv gobgpd /usr/local/bin/gobgpd && \ + rm gobgp_3.27.0_linux_amd64.tar.gz +COPY ./gobgpd.conf /root/gobgp/gobgpd.conf +COPY ./entrypoint.sh /root/gobgp/entrypoint.sh +COPY ./startup.sh /root/gobgp/startup.sh +RUN chmod +x /root/gobgp/entrypoint.sh && \ + chmod +x /root/gobgp/startup.sh +ENTRYPOINT ["/root/gobgp/entrypoint.sh"] diff --git a/gobgp/entrypoint.sh b/gobgp/entrypoint.sh new file mode 100644 index 0000000..272087e --- /dev/null +++ b/gobgp/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/bash +exec gobgpd -f /root/gobgp/gobgpd.conf & +exec /root/gobgp/startup.sh diff --git a/gobgp/gobgpd.conf b/gobgp/gobgpd.conf new file mode 100755 index 0000000..b736192 --- /dev/null +++ b/gobgp/gobgpd.conf @@ -0,0 +1,15 @@ +[global.config] + as = 400848 + router-id = "172.16.1.66" + +[[neighbors]] + [neighbors.config] + neighbor-address = "172.16.1.27" + peer-as = 400848 + route-flap-damping = "True" + [[neighbors.afi-safis]] + [neighbors.afi-safis.config] + afi-safi-name = "ipv4-unicast" + [[neighbors.afi-safis]] + [neighbors.afi-safis.config] + afi-safi-name = "ipv6-unicast" diff --git a/gobgp/requirements.txt b/gobgp/requirements.txt new file mode 100644 index 0000000..70d0b1b --- /dev/null +++ b/gobgp/requirements.txt @@ -0,0 +1,3 @@ +pymongo >= 4.8.0 +dnspython >= 2.6.1 +ipaddress >= 1.0.23 diff --git a/gobgp/startup.sh b/gobgp/startup.sh new file mode 100644 index 0000000..184ea84 --- /dev/null +++ b/gobgp/startup.sh @@ -0,0 +1,7 @@ +#!/bin/bash +## Production +. venv/bin/activate +gobgp monitor global rib -j | /var/tmp/gobgp_to_mongo.py +## +## Dev Test +# cat /var/tmp/log/bgp.dump.json | /var/tmp/gobgp_to_mongo.py diff --git a/gobgp_to_mongo.py b/gobgp_to_mongo.py new file mode 100755 index 0000000..4e52988 --- /dev/null +++ b/gobgp_to_mongo.py @@ -0,0 +1,200 @@ +#! /usr/bin/env python3 + +import sys +import json + +from pymongo.database import Database + +import bgp_attributes as BGP +from pymongo import MongoClient +import pymongo +from copy import copy +from datetime import datetime +import ipaddress +import logging + +# logging.basicConfig(level=logging.CRITICAL) +# logging.basicConfig(level=logging.DEBUG) + +# DEFAULTS - UPDATE ACCORDINGLY +MAX_PREFIX_HISTORY = 100 # None = unlimited (BGP flapping will likely kill DB if unlimited) + + +def db_connect(host='mongodb') -> Database: + """Return a connection to the Mongo Database.""" + client = MongoClient(host=host) + return client['bgp'] + + +def initialize_database(db: Database): + """Create indexes, and if the db contains any entries set them all to 'active': False""" + # db['bgp'].drop() + db['bgp'].create_index('nexthop') + db['bgp'].create_index('nexthop_asn') + db['bgp'].create_index([('nexthop', pymongo.ASCENDING), ('active', pymongo.ASCENDING)]) + db['bgp'].create_index([('nexthop_asn', pymongo.ASCENDING), ('active', pymongo.ASCENDING)]) + db['bgp'].create_index([('ip_version', pymongo.ASCENDING), ('active', pymongo.ASCENDING)]) + db['bgp'].create_index( + [('origin_asn', pymongo.ASCENDING), ('ip_version', pymongo.ASCENDING), ('active', pymongo.ASCENDING)]) + db['bgp'].create_index([('communities', pymongo.ASCENDING), ('active', pymongo.ASCENDING)]) + db['bgp'].create_index( + [('as_path.1', pymongo.ASCENDING), ('nexthop_asn', pymongo.ASCENDING), ('active', pymongo.ASCENDING)]) + db['bgp'].update_many( + {"active": True}, # Search for + {"$set": {"active": False}}) # Replace with + + +def get_update_entry(line): + """Read output from GoBGP from stdin and return a update entry *dict*""" + try: + update_list = json.loads(line) + for update_entry in update_list: + if 'error' in update_entry: + return None + else: + return update_entry + except Exception as err: + logging.error("Error in get_update_entry(line):", err) + return None + + +def compare_prefixes(new, old): + """ignore history, age, and active state, then compare prefix objects""" + new['history'] = new['age'] = new['active'] = None + old['history'] = old['age'] = old['active'] = None + if new == old: + return True + else: + return False + + +def community_32bit_to_string(number): + """Given a 32bit number, convert to standard bgp community format XXX:XX""" + if number != 0: + return f'{int(bin(number)[:-16], 2)}:{int(bin(number)[-16:], 2)}' # PEP 498 + + +def community_large_to_string(community: dict): + """Given a dict, convert to large bgp community format XXX:XXX:XXX""" + return f"{community['ASN']}:{community['LocalData1']}:{community['LocalData2']}" + + +def build_json(update_entry): + """Given an update entry from GoBGP, set the BGP attribue types as a + key/value dict and return""" + update_json = { # set defaults + '_id': update_entry['nlri']['prefix'], + 'ip_version': ipaddress.ip_address(update_entry['nlri']['prefix'].split('/', 1)[0]).version, + 'origin_asn': None, + 'nexthop': None, + 'nexthop_asn': None, + 'as_path': [], + 'med': 0, + 'local_pref': 0, + 'communities': [], + 'route_origin': None, + 'atomic_aggregate': None, + 'aggregator_as': None, + 'aggregator_address': None, + 'originator_id': None, + 'cluster_list': [], + 'withdrawal': False, + 'age': 0, + 'active': True, + 'history': [] + } + for attribute in update_entry['attrs']: + if attribute['type'] == BGP.ORIGIN: + update_json['route_origin'] = BGP.ORIGIN_CODE[attribute['value']] + if attribute['type'] == BGP.AS_PATH: + try: + update_json['as_path'] = attribute['as_paths'][0]['asns'] + update_json['nexthop_asn'] = update_json['as_path'][0] + update_json['origin_asn'] = update_json['as_path'][-1] + except Exception: + logging.debug(f'Error processing as_path: {attribute}') + logging.debug(f'Error processing as_path: {update_json["_id"]}') + if attribute['type'] == BGP.NEXT_HOP: + update_json['nexthop'] = attribute['nexthop'] + if attribute['type'] == BGP.MULTI_EXIT_DISC: + try: + update_json['med'] = attribute['metric'] + except Exception: + logging.debug(f'Error processing med: {attribute}') + if attribute['type'] == BGP.LOCAL_PREF: + try: + update_json['local_pref'] = attribute['value'] + except Exception: + logging.debug(f'Error processing local_pref: {attribute}') + if attribute['type'] == BGP.ATOMIC_AGGREGATE: + update_json['atomic_aggregate'] = True + if attribute['type'] == BGP.AGGREGATOR: + update_json['aggregator_as'] = attribute['as'] + update_json['aggregator_address'] = attribute['address'] + if attribute['type'] == BGP.COMMUNITY: + try: + for number in attribute['communities']: + update_json['communities'].append(community_32bit_to_string(number)) + except Exception: + logging.debug(f'Error processing communities: {attribute}') + if attribute['type'] == BGP.ORIGINATOR_ID: + update_json['originator_id'] = attribute['value'] + if attribute['type'] == BGP.CLUSTER_LIST: + update_json['cluster_list'] = attribute['value'] + if attribute['type'] == BGP.MP_REACH_NLRI: + update_json['nexthop'] = attribute['nexthop'] + if attribute['type'] == BGP.MP_UNREACH_NLRI: + logging.debug(f'Found MP_UNREACH_NLRI: {attribute}') + if attribute['type'] == BGP.EXTENDED_COMMUNITIES: + logging.debug(f'Found EXTENDED_COMMUNITIES: {attribute}') + if attribute['type'] == BGP.LARGE_COMMUNITIES: + try: + for community in attribute['value']: + update_json['communities'].append(community_large_to_string(community)) + except Exception: + logging.debug(f'Error processing LARGE_COMMUNITIES: {attribute}') + if 'withdrawal' in update_entry: + update_json['withdrawal'] = update_entry['withdrawal'] + update_json['active'] = False + if 'age' in update_entry: + update_json['age'] = datetime.fromtimestamp(update_entry['age']).strftime('%Y-%m-%d %H:%M:%S ') + 'UTC' + + return update_json + + +def update_prefix(prefix_from_gobgp, prefix_from_database): + if compare_prefixes(copy(prefix_from_gobgp), copy(prefix_from_database)): + prefix_from_gobgp['active'] = True # flip the active state to true + else: # diff between prefix_from_gobgp and prefix_from_database: update history + history_list = prefix_from_database['history'] + del prefix_from_database['active'] # delete house keeping keys from history objects + del prefix_from_database['history'] + if not history_list: # no history: create some + prefix_from_gobgp['history'].append(prefix_from_database) + else: # existing history: append to history list + history_list.insert(0, prefix_from_database) # insert on top of list, index 0 + prefix_from_gobgp['history'] = history_list[:MAX_PREFIX_HISTORY] # trim the history list if MAX is set + return prefix_from_gobgp + + +def main(): + db = db_connect() + initialize_database(db) + for line in sys.stdin: + try: + prefix_from_gobgp = build_json(get_update_entry(line)) + + prefix_from_database = db['bgp'].find_one({'_id': prefix_from_gobgp['_id']}) + + if prefix_from_database: + updated_prefix = update_prefix(prefix_from_gobgp, prefix_from_database) + db['bgp'].update_one({"_id": prefix_from_database['_id']}, {'$set': updated_prefix}, upsert=True) + else: + db['bgp'].update_one({"_id": prefix_from_gobgp['_id']}, {'$set': prefix_from_gobgp}, upsert=True) + + except TypeError as e: + print(f"TypeError {e} in Line: {line}") + + +if __name__ == "__main__": + sys.exit(main())
+
+ + + +
+
+
+
+

ASN{{source_asn}}

+

{{source_asn_name}}

+
+
+
+
+ + + + +
+
+
+
+
+
+ + + + +
+
+
+
+
+
+ + + +
+
+
+
+
+
+
0
+

Peer Count

+
+

+

Active egress BGP peers

+
+
+

Loading..

+
+
+
+
+
+
0
+

IPv4 Prefixes

+
+

+

IPv4 BGP Table Size

+
+
+

Loading..

+
+
+
+
+
+
0
+

IPv6 Prefixes

+
+

+

IPv6 BGP Table Size

+
+
+

Loading..

+
+
+
+
+
+
0
+

Next Hop Addresses

+
+

+

Unique Egress IP Addresses

+
+
+

Loading..

+
+
+
+ +
+
+
+
+
0
+

Average AS Path Length

+
+

+

ASN hops to destination (lower is better)

+
+
+

Loading..

+
+
+
+
+
+
0
+

Customer IPv4 Prefixes

+
+

+

Customer & Orginated IPv4 Prefix Count

+
+
+

Loading..

+
+
+
+
+
+
0
+

Customer IPv6 Prefixes

+
+

+

Customer & Orginated IPv6 Prefix Count

+
+
+

Loading..

+
+
+
+
+
+
0
+

BGP Customers

+
+

+

Downstream BGP connected ASNs

+
+
+

Loading..

+
+
+
+ +
+
+
+
+

Peer Data Updated every 300s

+
+
+
+
+
+ + + + + + + + + + + + +
ASNNameIPv4 Prefixes
Originated
IPv4 Prefixes
NextHop
IPv6 Prefixes
Originated
IPv6 Prefixes
NextHop
Downstream
ASN Count
+
+
+ +
+
+
+

Top Peers (Prefixes Received)

+ +
+
+
    + {% for peer in top_peers %} +
  • + + + +
    + ASN {{ peer.asn }} +

    {{ '{0:,}'.format(peer.count) }} Prefixes

    +

    {{ peer.name }} +

    +
    +
  • + {% endfor %} +
+
+
+ +
+
+
+
+ + + +
+
+
+
+

BGP Prefix Distributions Prefix Count

+
+
+
+
+
+
+
+

Peering Prefix Count

+
+
+

Transit vs. Peering

+
+
+
+
+
+
+
+
+
+ +
+
+
+

IPv4 Network Mask Prefix Count

+
+
+
+
+
+
+
+ + + +
+
+
+

IPv6 Network Mask Prefix Count

+
+
+
+
+
+
+
+
+ +
+ +
+
+
+ + + +
+
+ BGP Dashboard at Github +
+ Gentelella - Bootstrap Admin Template by Colorlib +
+
+
+ +
+