├── start-browser.bat ├── extra └── start-server.sh ├── app ├── static │ ├── favicon.ico │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ ├── js │ │ ├── npm.js │ │ ├── plugins │ │ │ ├── jqplot.pointLabels.js │ │ │ └── jqplot.categoryAxisRenderer.js │ │ └── bootstrap.min.js │ └── css │ │ ├── starter-template.css │ │ ├── jquery.jqplot.min.css │ │ ├── jquery.jqplot.css │ │ ├── bootstrap-theme.min.css │ │ └── bootstrap-theme.css ├── tests │ ├── reference.dat │ ├── common.py │ ├── test_local_python.py │ ├── randomized_combo_tester_v4.py │ ├── test_upstream.py │ └── compare_html_sources.py ├── views │ ├── reporting.html │ ├── base.html │ └── index.html ├── getcsv.py ├── reporting.py ├── server.py └── evaluator.py ├── requirements.txt ├── images ├── Python-3.8.x.png ├── Python-3.9.x.png └── start-server.png ├── start-server.bat ├── .gitignore └── README.md /start-browser.bat: -------------------------------------------------------------------------------- 1 | start "IPIP-NEO" "http://localhost:8888" 2 | -------------------------------------------------------------------------------- /extra/start-server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd app 4 | python3 server.py 5 | -------------------------------------------------------------------------------- /app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kholia/IPIP-NEO-PI/HEAD/app/static/favicon.ico -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | bottle 2 | ipython 3 | pyquery 4 | requests 5 | selenium 6 | selenium-wire 7 | -------------------------------------------------------------------------------- /images/Python-3.8.x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kholia/IPIP-NEO-PI/HEAD/images/Python-3.8.x.png -------------------------------------------------------------------------------- /images/Python-3.9.x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kholia/IPIP-NEO-PI/HEAD/images/Python-3.9.x.png -------------------------------------------------------------------------------- /images/start-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kholia/IPIP-NEO-PI/HEAD/images/start-server.png -------------------------------------------------------------------------------- /app/static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kholia/IPIP-NEO-PI/HEAD/app/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /app/static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kholia/IPIP-NEO-PI/HEAD/app/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /app/static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kholia/IPIP-NEO-PI/HEAD/app/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /app/static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kholia/IPIP-NEO-PI/HEAD/app/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /app/tests/reference.dat: -------------------------------------------------------------------------------- 1 | 128211623 910113 user India 2 | 455454245414355144252442444444435454354214445435053442424254 3 | 455453415314242354554251515543245452445414245444452135425154 4 | -------------------------------------------------------------------------------- /app/views/reporting.html: -------------------------------------------------------------------------------- 1 | %#https://bottlepy.org/docs/0.12/tutorial_app.html 2 | %#template to generate a HTML table from a list of tuples (or list of lists, or tuple of tuples or ...) 3 |

Historical Reports:

4 | 5 | %for row in rows: 6 | 7 | %for col in row: 8 | 9 | %end 10 | 11 | %end 12 |
{{col}}
13 | -------------------------------------------------------------------------------- /app/static/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /app/getcsv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Extracts contents of results.db into results.csv file.""" 4 | 5 | import sqlite3 6 | import csv 7 | 8 | 9 | con = sqlite3.connect('results.db') 10 | 11 | with con: 12 | 13 | cur = con.cursor() 14 | cur.execute("SELECT * FROM RESULTS") 15 | 16 | rows = cur.fetchall() 17 | 18 | with open("results.csv", "a") as f: 19 | writer = csv.writer(f, delimiter=',') 20 | for row in rows: 21 | timestamp, gender, age, nick, country, answers = row 22 | output = [nick, gender, age, country, timestamp, answers] 23 | writer.writerow(output) 24 | -------------------------------------------------------------------------------- /app/static/css/starter-template.css: -------------------------------------------------------------------------------- 1 | body { 2 | } 3 | 4 | .starter-template { 5 | padding: 40px 15px; 6 | } 7 | 8 | .results img { 9 | height: 20px; 10 | } 11 | 12 | td { text-align: center;} 13 | #main td:nth-child(1) { text-align: center;} 14 | #main td:nth-child(2) { text-align: left; padding-left:8px;} 15 | #main td:nth-child(2) { width: 28%;} 16 | #main td:nth-child(3) { width: 14%;} 17 | #main td:nth-child(4) { width: 13%;} 18 | #main td:nth-child(5) { width: 17%;} 19 | #main td:nth-child(6) { width: 12%;} 20 | #main td { height: 70px;} 21 | 22 | .note { 23 | font-size: 0.8em; 24 | } 25 | 26 | .jqplot-yaxis-tick { 27 | white-space: nowrap; 28 | } 29 | -------------------------------------------------------------------------------- /app/tests/common.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Graph Results: 76, 82, 64, 63, 88, 26, 84 (EXTRAVERSION, Friendliness, Gregariousness...) 4 | sanswers = "455454245414355144252442444444435454354214445435053442424254" + "455453415314242354554251515543245452445414245444452135425154" 5 | 6 | # 1 means first visible button, 5 means last visible button. The 1st radio button may have value="5" internally! 7 | answers = [4, 3, 4, 3, 2, 5, 2, 3, 1, 4, 5, 3, 1, 5, 4, 3, 5, 3, 4, 5, 4, 5, 4, 3, 4, 4, 2, 3, 2, 4, 4, 5, 2, 4, 1, 3, 2, 3, 2, 2, 3, 5, 5, 1, 1, 4, 3, 5, 5, 4, 2, 5, 2, 5, 5, 4, 3, 5, 5, 1, 5, 3, 1, 2, 3, 1, 2, 1, 1, 5, 3, 1, 3, 2, 4, 5, 1, 5, 5, 2, 5, 2, 5, 5, 1, 1, 1, 3, 2, 2, 4, 1, 5, 2, 1, 4, 3, 1, 5, 2, 2, 4, 4, 2, 2, 1, 5, 4, 4, 3, 2, 1, 4, 1, 1, 5, 1, 1, 4, 1] 8 | 9 | # answers = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] 10 | 11 | N = 120 # 120 questions 12 | -------------------------------------------------------------------------------- /app/views/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{title or 'No title'}} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | %include 24 | 25 | 26 | -------------------------------------------------------------------------------- /start-server.bat: -------------------------------------------------------------------------------- 1 | :: https://ss64.com/nt/syntax-variables.html 2 | 3 | cd app 4 | 5 | set LAUNCHED=F 6 | set PYTHON_FOLDER_NEWEST=%LocalAppData%\Programs\Python\Python39-32 7 | set PYTHON_FOLDER=%LocalAppData%\Programs\Python\Python38-32 8 | set PYTHON_FOLDER_64=%LocalAppData%\Programs\Python\Python38 9 | set PYTHON_FOLDER_OLD=%HOMEDRIVE%\Python34 10 | 11 | :: Look for Python 3.9.x 32-bit 12 | :: where python.exe # doesn't work on XP 13 | if defined LocalAppData ( 14 | if exist %PYTHON_FOLDER_NEWEST%\python.exe ( 15 | rem Python 3.9.x found! 16 | set LAUNCHED=T 17 | %PYTHON_FOLDER_NEWEST%\python.exe server.py 18 | ) 19 | ) 20 | 21 | :: Look for Python 3.8.x 32-bit 22 | if defined LocalAppData ( 23 | if exist %PYTHON_FOLDER%\python.exe ( 24 | rem Python 3.8.x found! 25 | set LAUNCHED=T 26 | %PYTHON_FOLDER%\python.exe server.py 27 | ) 28 | ) 29 | 30 | :: Look for Python 3.8.x 64-bit 31 | if defined LocalAppData ( 32 | if exist %PYTHON_FOLDER_64%\python.exe ( 33 | rem Python 3.8.x found! 34 | set LAUNCHED=T 35 | %PYTHON_FOLDER_64%\python.exe server.py 36 | ) 37 | ) 38 | :: Look for Python 3.4.x 39 | if "%LAUNCHED%"=="F" ( 40 | rem Looking for Python 3.4.x 41 | if exist %PYTHON_FOLDER_OLD%\python.exe ( 42 | rem Python 3.4.x found! 43 | set LAUNCHED=T 44 | %PYTHON_FOLDER_OLD%\python.exe server.py 45 | ) 46 | ) 47 | 48 | :: Look for Python in PATH 49 | if "%LAUNCHED%"=="F" ( 50 | rem Looking for Python in PATH 51 | set LAUNCHED=T 52 | python server.py 53 | ) 54 | 55 | @pause 56 | -------------------------------------------------------------------------------- /app/reporting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Historial reporting module. 5 | """ 6 | 7 | import json 8 | import datetime 9 | import collections 10 | 11 | import bottle 12 | 13 | 14 | def show(request, db=None): 15 | """API endpoint.""" 16 | 17 | results = db.execute("SELECT * from RESULTS").fetchall() 18 | 19 | return bottle.template('reporting', rows=results) 20 | 21 | 22 | def evaluate(request, db=None): 23 | 24 | """Personality evaluation logic.""" 25 | 26 | SEP, SEFP, LO, HI, SE, SAP, SAFP, SA, SC, SCP, SCFP, flev, SOP, SOFP, SO, \ 27 | Nick, Country, SNP, SNFP, Category, SN, Sex, Age, Q = evaluate_api(request) 28 | 29 | # Check sex and age 30 | if Sex != "Male" and Sex != "Female": 31 | return """You did not indicate your sex at the beginning of the 32 | inventory. Your answers cannot be normed properly unless you indicate 33 | whether you are male or female. Please return to the inventory and indicate 34 | your sex.""" 35 | 36 | if Age < 10: 37 | return """You did not indicate how old you are at the beginning of the 38 | inventory, or you typed in an age that is too young. Your answers cannot be 39 | normed properly unless type in a valid age. Please return to the inventory 40 | and change your response.""" 41 | 42 | # Save Data 43 | if db: 44 | responses = " ".join([str(i) for i in Q[1:121]]) 45 | 46 | db.execute('insert into RESULTS values(?, ?, ?, ?, ?, ?)', 47 | (datetime.datetime.now(), Sex, Age, Nick, Country, 48 | responses)) 49 | db.commit() 50 | 51 | return bottle.template( 52 | 'results', SEP=SEP, SEFP=SEFP, 53 | LO=45, HI=55, SE=SE, SAP=SAP, SAFP=SAFP, SA=SA, 54 | SC=SC, SCP=SCP, SCFP=SCFP, flev=flev, 55 | SOP=SOP, SOFP=SOFP, 56 | SO=SO, Nick=Nick, Country=Country, 57 | SNP=SNP, SNFP=SNFP, Category=Category, 58 | SN=SN) 59 | -------------------------------------------------------------------------------- /app/tests/test_local_python.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | The XPath stuff was buggy. We moved away from it and things are fine now! 5 | 6 | https://www.softwaretestinghelp.com/radio-buttons-in-selenium/ 7 | """ 8 | 9 | import time 10 | import unittest 11 | import collections 12 | 13 | from common import answers 14 | 15 | from selenium import webdriver 16 | from selenium.webdriver.support.ui import Select 17 | from selenium.common.exceptions import NoSuchElementException 18 | 19 | from pyquery import PyQuery as pq 20 | 21 | # Globals 22 | m = {} 23 | debug = False 24 | 25 | class Test(unittest.TestCase): 26 | def setUp(self): 27 | self.driver = webdriver.Firefox() 28 | self.driver.implicitly_wait(30) 29 | self.base_url = "http://localhost:8888/" 30 | 31 | def test_(self): 32 | driver = self.driver 33 | driver.get(self.base_url) 34 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() 35 | driver.find_element_by_name("Nick").clear() 36 | driver.find_element_by_name("Nick").send_keys("hello") 37 | driver.find_element_by_name("Sex").click() 38 | driver.find_element_by_name("Age").clear() 39 | driver.find_element_by_name("Age").send_keys("28") 40 | 41 | Select(driver.find_element_by_name('Country')).select_by_index(3) 42 | 43 | if debug: 44 | end = 9 45 | else: 46 | end = 120 47 | 48 | for i in range(0, end): 49 | name = "Q%s" % (i+1) 50 | answer_in_range = answers[i]-1 51 | print(name, answers[i]) 52 | buttons = driver.find_elements_by_name(name) 53 | buttons[answer_in_range].click() 54 | """ 55 | xpath = "(//input[@name='Q%s'][@value=%d])" % (i+1, answers[i]) 56 | driver.find_element_by_xpath(xpath).click() 57 | print(xpath, answers[i]) 58 | """ 59 | 60 | if debug: 61 | time.sleep(120) 62 | """ 63 | if debug: 64 | from IPython import embed 65 | embed() 66 | """ 67 | 68 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() 69 | 70 | def tearDown(self): 71 | time.sleep(600) 72 | 73 | self.driver.quit() 74 | self.assertEqual([], self.verificationErrors) 75 | 76 | if __name__ == "__main__": 77 | unittest.main() 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | sipipitem.dat 2 | *.pyc 3 | *.bak 4 | *.db 5 | *.csv 6 | 7 | # https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore follows 8 | 9 | # Byte-compiled / optimized / DLL files 10 | __pycache__/ 11 | *.py[cod] 12 | *$py.class 13 | 14 | # C extensions 15 | *.so 16 | 17 | # Distribution / packaging 18 | .Python 19 | build/ 20 | develop-eggs/ 21 | dist/ 22 | downloads/ 23 | eggs/ 24 | .eggs/ 25 | lib/ 26 | lib64/ 27 | parts/ 28 | sdist/ 29 | var/ 30 | wheels/ 31 | share/python-wheels/ 32 | *.egg-info/ 33 | .installed.cfg 34 | *.egg 35 | MANIFEST 36 | 37 | # PyInstaller 38 | # Usually these files are written by a python script from a template 39 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 40 | *.manifest 41 | *.spec 42 | 43 | # Installer logs 44 | pip-log.txt 45 | pip-delete-this-directory.txt 46 | 47 | # Unit test / coverage reports 48 | htmlcov/ 49 | .tox/ 50 | .nox/ 51 | .coverage 52 | .coverage.* 53 | .cache 54 | nosetests.xml 55 | coverage.xml 56 | *.cover 57 | *.py,cover 58 | .hypothesis/ 59 | .pytest_cache/ 60 | cover/ 61 | 62 | # Translations 63 | *.mo 64 | *.pot 65 | 66 | # Django stuff: 67 | *.log 68 | local_settings.py 69 | db.sqlite3 70 | db.sqlite3-journal 71 | 72 | # Flask stuff: 73 | instance/ 74 | .webassets-cache 75 | 76 | # Scrapy stuff: 77 | .scrapy 78 | 79 | # Sphinx documentation 80 | docs/_build/ 81 | 82 | # PyBuilder 83 | .pybuilder/ 84 | target/ 85 | 86 | # Jupyter Notebook 87 | .ipynb_checkpoints 88 | 89 | # IPython 90 | profile_default/ 91 | ipython_config.py 92 | 93 | # pyenv 94 | # For a library or package, you might want to ignore these files since the code is 95 | # intended to run in multiple environments; otherwise, check them in: 96 | # .python-version 97 | 98 | # pipenv 99 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 100 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 101 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 102 | # install all needed dependencies. 103 | #Pipfile.lock 104 | 105 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 106 | __pypackages__/ 107 | 108 | # Celery stuff 109 | celerybeat-schedule 110 | celerybeat.pid 111 | 112 | # SageMath parsed files 113 | *.sage.py 114 | 115 | # Environments 116 | .env 117 | .venv 118 | env/ 119 | venv/ 120 | ENV/ 121 | env.bak/ 122 | venv.bak/ 123 | 124 | # Spyder project settings 125 | .spyderproject 126 | .spyproject 127 | 128 | # Rope project settings 129 | .ropeproject 130 | 131 | # mkdocs documentation 132 | /site 133 | 134 | # mypy 135 | .mypy_cache/ 136 | .dmypy.json 137 | dmypy.json 138 | 139 | # Pyre type checker 140 | .pyre/ 141 | 142 | # pytype static type analyzer 143 | .pytype/ 144 | 145 | # Cython debug symbols 146 | cython_debug/ 147 | -------------------------------------------------------------------------------- /app/tests/randomized_combo_tester_v4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # pylint: disable=C0103,R0912,R0914,R0915,W0613 3 | 4 | """ 5 | Randomly compares the output of the upstream website against the local website. 6 | """ 7 | 8 | import sys 9 | import random 10 | import signal 11 | 12 | import requests 13 | from pyquery import PyQuery as pq 14 | 15 | stats = {"pass_count": 0, "fail_count": 0} 16 | 17 | 18 | def signal_handler(sig, frame): 19 | """ 20 | Ctrl+C handler" 21 | """ 22 | print('\n') 23 | print("[+] Total PASS count is (%s)", stats["pass_count"]) 24 | print("[!] Total FAIL count is (%s)", stats["fail_count"]) 25 | sys.exit(0) 26 | 27 | 28 | def run(): 29 | """ 30 | Run one random test case. 31 | 32 | Returns True for PASS. 33 | 34 | Returns False for FAIL. 35 | """ 36 | 37 | nick = "Testing Please Ignore" 38 | age = "28" 39 | 40 | N = 120 # 120 questions 41 | answers = [] 42 | for i in range(0, N): 43 | answers.append(random.randint(1, 5)) 44 | # answers.append(3) 45 | 46 | # Common data 47 | data = {"Nick": nick, "Sex": "Male", "Age": age, "Country": "Afghanistan"} 48 | for i in range(0, N): 49 | data["Q%s" % (i+1)] = answers[i] 50 | 51 | # Test upstream first 52 | m = {} 53 | # base_url = "http://www.personal.psu.edu/cgi-bin/users/j/5/j5j/IPIP/shortipipneo3.cgi" 54 | base_url = "http://localhost/cgi-bin/shortipipneo3.cgi" 55 | r = requests.post(base_url, data=data) 56 | d = pq(r.text) 57 | for table in d("table"): 58 | trs = list(pq(table)("tr")) 59 | trs = trs[1:] # skip over table header ("DOMAIN/Facet") 60 | for tr in trs: 61 | ds = pq(tr) 62 | tds = list(ds("td")) 63 | label, score = tds[0:2] 64 | score = score.text 65 | label = label.text.lstrip("..") 66 | m[label] = int(score) 67 | 68 | # Test local now 69 | base_url = "http://localhost:8888/results_api" 70 | n = {} 71 | r = requests.post(base_url, data=data) 72 | n = r.json() 73 | 74 | failed = False 75 | for k, v in n.items(): 76 | if v != m.get(k, None): 77 | # print("[!] FAILED for (Local, %s, %s) vs (Upstream, %s)" % (k, v, m.get(k, None))) 78 | failed = True 79 | 80 | if not failed: 81 | stats["pass_count"] = stats["pass_count"] + 1 82 | else: 83 | stats["fail_count"] = stats["fail_count"] + 1 84 | L = 150 85 | print("-" * L) 86 | print(data) 87 | print("Upstream:", m) 88 | print("Local:", n) 89 | for k, v in n.items(): 90 | if v == m.get(k, None): 91 | print("[!] FAILED for (Local, %s, %s) vs (Upstream, %s)" % (k, v, m.get(k, None))) 92 | print("-" * L, "\n") 93 | 94 | if __name__ == "__main__": 95 | signal.signal(signal.SIGINT, signal_handler) 96 | print('Press Ctrl+C to stop testing and print stats...') 97 | while True: 98 | run() 99 | -------------------------------------------------------------------------------- /app/static/css/jquery.jqplot.min.css: -------------------------------------------------------------------------------- 1 | .jqplot-xaxis,.jqplot-xaxis-label{margin-top:10px}.jqplot-x2axis,.jqplot-x2axis-label{margin-bottom:10px}.jqplot-target{position:relative;color:#666;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:1em}.jqplot-axis{font-size:.75em}.jqplot-yaxis{margin-right:10px}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px}.jqplot-axis-tick,.jqplot-x2axis-tick,.jqplot-xaxis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick,.jqplot-yaxis-tick{position:absolute;white-space:pre}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom}.jqplot-yaxis-tick{right:0;top:15px;text-align:right}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px;z-index:2;font-size:1.5em}.jqplot-x2axis-label,.jqplot-xaxis-label,.jqplot-yMidAxis-label,.jqplot-yaxis-label{font-size:11pt;position:absolute}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap}.jqplot-yaxis-label{margin-right:10px}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute}.jqplot-meterGauge-tick{font-size:.75em;color:#999}.jqplot-meterGauge-label{font-size:1em;color:#999}table.jqplot-table-legend{margin:12px}table.jqplot-cursor-legend,table.jqplot-table-legend{background-color:rgba(255,255,255,.6);border:1px solid #ccc;position:absolute;font-size:.75em}td.jqplot-table-legend{vertical-align:middle}td.jqplot-seriesToggle:active,td.jqplot-seriesToggle:hover{cursor:pointer}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through}div.jqplot-table-legend-swatch-outline{border:1px solid #ccc;padding:1px}div.jqplot-table-legend-swatch{width:0;height:0;border-width:5px 6px;border-style:solid}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em}.jqplot-canvasOverlay-tooltip,.jqplot-cursor-tooltip,.jqplot-highlighter-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,.5);padding:1px}.jqplot-point-label{font-size:.75em;z-index:2}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em}.jqplot-error{text-align:center}.jqplot-error-message{position:relative;top:46%;display:inline-block}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%)}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,.7)}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,.3)} -------------------------------------------------------------------------------- /app/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Main app server. 5 | """ 6 | 7 | import sqlite3 8 | import traceback 9 | 10 | import evaluator 11 | import reporting 12 | 13 | import bottle 14 | 15 | bottle.BaseRequest.MAX_PARAMS = 10000 16 | app = bottle.Bottle() 17 | CFG = {'DB': None} 18 | 19 | @app.route('/') 20 | def ipipneo120(): 21 | """ 22 | Show the 'homepage'. 23 | """ 24 | 25 | return bottle.template('index') 26 | 27 | 28 | @app.route('/shortipipneo', method='POST') 29 | def shortipipneo(): 30 | """ 31 | Show the 'short test'. 32 | """ 33 | # print(bottle.request.body.readlines()) 34 | return bottle.template('shortipipneo') 35 | 36 | 37 | @app.route('/results', method='POST') 38 | def results(): 39 | """ 40 | Generate and display the 'results' page. 41 | """ 42 | # print(bottle.request.body.readlines()) 43 | return evaluator.evaluate(bottle.request, CFG['DB']) 44 | 45 | @app.route('/reporting', method='GET') 46 | def show(): 47 | """ 48 | Historial reporting page 49 | """ 50 | # print(bottle.request.body.readlines()) 51 | return reporting.show(bottle.request, CFG['DB']) 52 | 53 | @app.route('/results_api', method='POST') 54 | def results_api(): 55 | """ 56 | The "results API". 57 | """ 58 | return evaluator.evaluate_api(bottle.request) 59 | 60 | 61 | @app.route('/graph', method='GET') 62 | def graph(): 63 | """ 64 | Displays 'graph'. 65 | """ 66 | return bottle.template("graph") 67 | 68 | 69 | # Static Routes 70 | @app.get(r'/js/') 71 | def javascripts(filename): 72 | """ 73 | Static handler for JS files. 74 | """ 75 | return bottle.static_file(filename, root='static/js') 76 | 77 | @app.get(r'/favicon.ico') 78 | def favicon(): 79 | """ 80 | Static handler for favicon. 81 | """ 82 | 83 | return bottle.static_file("favicon.ico", root='static') 84 | 85 | @app.get(r'/css/') 86 | def stylesheets(filename): 87 | """ 88 | Static handler for CSS files. 89 | """ 90 | return bottle.static_file(filename, root='static/css') 91 | 92 | 93 | @app.get(r'/') 94 | def images(filename): 95 | """ 96 | Handler for images. 97 | """ 98 | return bottle.static_file(filename, root='static/images') 99 | 100 | 101 | @app.get(r'/') 102 | def fonts(filename): 103 | """ 104 | Handler for fonts. 105 | """ 106 | return bottle.static_file(filename, root='static/fonts') 107 | 108 | 109 | def main(): 110 | """ 111 | Program starts here. 112 | """ 113 | # setup database 114 | dbfile = "results.db" 115 | start = True 116 | table_create_sql = """CREATE TABLE IF NOT EXISTS RESULTS ( 117 | TIMESTAMP TIMESTAMP NOT NULL, 118 | Gender TEXT NOT NULL, 119 | Age INT NOT NULL, 120 | Nick TEXT NOT NULL, 121 | Country TEXT NOT NULL, 122 | Responses TEXT NOT NULL);""" 123 | try: 124 | CFG['DB'] = sqlite3.connect(dbfile) 125 | CFG['DB'].execute(table_create_sql) 126 | except sqlite3.DatabaseError: 127 | start = False 128 | traceback.print_exc() 129 | 130 | except sqlite3.OperationalError: 131 | start = False 132 | traceback.print_exc() 133 | 134 | if start: 135 | bottle.run(app=app, host='localhost', port=8888, 136 | debug=True, reloader=True) 137 | 138 | if __name__ == "__main__": 139 | main() 140 | -------------------------------------------------------------------------------- /app/tests/test_upstream.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | After disabling XPath stuff, things are fine! 5 | """ 6 | 7 | import time 8 | import unittest 9 | import collections 10 | 11 | from common import answers 12 | 13 | from selenium import webdriver 14 | from selenium.webdriver.support.ui import Select 15 | from selenium.common.exceptions import NoSuchElementException 16 | 17 | from pyquery import PyQuery as pq 18 | 19 | # Globals 20 | m = {} 21 | debug = False 22 | 23 | class Test(unittest.TestCase): 24 | def setUp(self): 25 | self.driver = webdriver.Firefox() 26 | self.driver.implicitly_wait(30) 27 | self.base_url = "http://www.personal.psu.edu" 28 | self.verificationErrors = [] 29 | self.accept_next_alert = True 30 | 31 | def test_(self): 32 | driver = self.driver 33 | driver.get(self.base_url + "/~j5j/IPIP/ipipneo120.htm") 34 | driver.find_element_by_name("Risk").click() 35 | driver.find_element_by_name("Accuracy").click() 36 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() 37 | driver.find_element_by_name("Nick").clear() 38 | driver.find_element_by_name("Nick").send_keys("hello") 39 | driver.find_element_by_name("Sex").click() 40 | driver.find_element_by_name("Age").clear() 41 | driver.find_element_by_name("Age").send_keys("28") 42 | 43 | Select(driver.find_element_by_name('Country')).select_by_index(3) 44 | 45 | if debug: 46 | end = 10 47 | else: 48 | end = 61 49 | 50 | for i in range(1, end): # answers 1st page 51 | if answers[i - 1] == 0: 52 | continue 53 | name = "Q%s" % i 54 | answer_in_range = answers[i - 1] - 1 55 | buttons = driver.find_elements_by_name("Q%s" % i) 56 | buttons[answer_in_range].click() 57 | """ 58 | xpath = "(//input[@name='Q%s'])[%d]" % (i, answers[i - 1]) 59 | print(xpath) 60 | driver.find_element_by_xpath(xpath).click() 61 | """ 62 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() 63 | 64 | for i in range(61, 121): # answer 2nd page 65 | if answers[i - 1] == 0: 66 | continue 67 | name = "Q%s" % i 68 | answer_in_range = answers[i - 1] - 1 69 | buttons = driver.find_elements_by_name("Q%s" % i) 70 | buttons[answer_in_range].click() 71 | """ 72 | xpath = "(//input[@name='Q%s'])[%d]" % (i, answers[i - 1]) 73 | print(xpath) 74 | driver.find_element_by_xpath(xpath).click() 75 | """ 76 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() 77 | 78 | def tearDown(self): 79 | # Extract results data 80 | driver = self.driver 81 | page_source = driver.page_source 82 | d = pq(page_source) 83 | for table in d("table"): 84 | trs = list(pq(table)("tr")) 85 | trs = trs[1:] # skip over table header ("DOMAIN/Facet") 86 | for tr in trs: 87 | ds = pq(tr) 88 | tds = list(ds("td")) 89 | label, score = tds[0:2] 90 | score = score.text 91 | label = label.text.lstrip("..") 92 | m[label] = score 93 | print(m) 94 | 95 | debug = True 96 | if debug: 97 | from IPython import embed 98 | embed() 99 | if debug: 100 | time.sleep(3600) 101 | self.driver.quit() 102 | self.assertEqual([], self.verificationErrors) 103 | 104 | if __name__ == "__main__": 105 | unittest.main() 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### IPIP-NEO 2 | 3 | This project is a `Python 3 port` of Dr. John's IPIP-NEO software. This port 4 | is able to run offline (disconnected from the internet). 5 | 6 | IPIP-NEO-120 is an IPIP version of the NEO-PI-R test. 7 | 8 | "The IPIP-NEO is not identical to the original NEO PI-R, but in my opinion it 9 | is close enough to serve as a good substitute. More and more people are 10 | beginning to use it in published research, so its acceptance is growing." - Dr. 11 | Johnson 12 | 13 | #### Upstream Resources 14 | 15 | * http://www.personal.psu.edu/j5j/IPIP/ (original website) 16 | 17 | * Dr John A. Johnson (j5j [at] psu [dot] edu) 18 | 19 | #### Installation on Windows 20 | 21 | 1. Download and install `Python 3.8.10 32-bit` from [this link](https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe). 22 | 23 | Please select the `Add Python 3.8 to PATH` option in the Python installer. 24 | 25 | ![Python 3.8.x installation](./images/Python-3.8.x.png) 26 | 27 | Note: For older `Windows XP` systems, install `Python 3.4.4` from [this link](https://www.python.org/ftp/python/3.4.4/python-3.4.4.msi). 28 | Please select the `Install for all users` option in the Python installer. 29 | 30 | 2. Download and extract the `IPIP-NEO-PI` software ZIP file. Click [here](https://github.com/kholia/IPIP-NEO-PI/archive/21.06.zip) to download. 31 | 32 | 3. Run the `IPIP-NEO web server` by clicking on the `start-server.bat` file. After 33 | doing so, you should see something like, 34 | 35 | ![Server Started](./images/start-server.png) 36 | 37 | 4. Open the IPIP-NEO test in the browser by clicking on the `start-browser.bat` file or by clicking [here](http://localhost:8888). 38 | 39 | 5. [OPTIONAL] We recommend using the `Firefox` web browser. Firefox can be downloaded from the https://www.mozilla.org/ website. 40 | 41 | #### Reporting 42 | 43 | The test results are saved in a local SQLite database file called `app\results.db`. 44 | 45 | You can view this SQLite database file using the https://sqlitebrowser.org/ 46 | software. 47 | 48 | To view historical tests, click [here](http://localhost:8888/reporting). Doing 49 | so opens the http://localhost:8888/reporting page in your browser. 50 | 51 | #### Internal Components 52 | 53 | * Bootstrap 54 | 55 | * Bottle 0.12.19 56 | 57 | * jqPlot 1.0.9.d96a669 58 | 59 | * Selenium 60 | 61 | #### Credits 62 | 63 | * Dr John A. Johnson 64 | 65 | * Dhiru Kholia 66 | 67 | * Dr KJ Divina Kumar 68 | 69 | #### Notes 70 | 71 | All development work happens on Linux (Ubuntu). 72 | 73 | For testing, we run Windows XP, 7, and 10 Virtual Machines using VirtualBox. 74 | 75 | For testing against the upstream website, use `time python3 76 | randomized_combo_tester_v4.py` command. 77 | 78 | #### License 79 | 80 | Public Domain. See https://ipip.ori.org/newPermission.htm for more information. 81 | 82 | #### Resources 83 | 84 | * http://www.personal.psu.edu/j5j/IPIP/ipipneo300.htm 85 | 86 | * http://www.personal.psu.edu/~j5j/IPIP/ipipneo120.htm 87 | 88 | * http://www.personal.psu.edu/~j5j/papers/ConferencePapers/2011ARP.pdf 89 | 90 | * http://www.personal.psu.edu/j5j/IPIP/ 91 | 92 | * http://www.personal.psu.edu/faculty/j/5/j5j/papers/IPIP2006.pdf 93 | 94 | * http://personality-project.org/pmc.html 95 | 96 | * https://ipip.ori.org/ 97 | 98 | * https://ipip.ori.org/newneofacetskey.htm 99 | 100 | * http://personality-project.org/r/psych/ 101 | 102 | * http://sapa-project.org/ 103 | 104 | * http://personality-project.org/pmc.html 105 | 106 | * http://www.personality-project.org/r/book/ 107 | 108 | * http://personality-testing.info/ 109 | 110 | * http://pages.uoregon.edu/sanjay/bigfive.html 111 | 112 | * http://en.wikipedia.org/wiki/Revised_NEO_Personality_Inventory 113 | 114 | * https://en.wikipedia.org/wiki/International_Personality_Item_Pool 115 | -------------------------------------------------------------------------------- /app/tests/compare_html_sources.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import time 4 | import unittest 5 | import collections 6 | 7 | from common import answers 8 | 9 | from selenium import webdriver 10 | from selenium.webdriver.support.ui import Select 11 | from selenium.common.exceptions import NoSuchElementException 12 | 13 | from pyquery import PyQuery as pq 14 | 15 | 16 | def test_local_python_site(): 17 | """ 18 | Test local site 19 | """ 20 | items = [] 21 | driver = webdriver.Firefox() 22 | base_url = "http://localhost:8888/" 23 | driver.get(base_url) 24 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() 25 | page_source = driver.page_source 26 | d = pq(page_source) # use pyquery to extract the table values 27 | main_table = d("table[id='main']") 28 | trs = list(pq(main_table)("tr")) 29 | for tr in trs: 30 | ds = pq(tr) 31 | tds = list(ds("td")) 32 | tds = tds[1:] # skip index number 33 | for td in tds: 34 | text = (" ").join(td.text_content().replace("\n", " ").split()) # cleanup terrible html text and canonicalize it! 35 | radio_button = pq(td)("input") 36 | val = radio_button.val() 37 | items.append([text, val]) # store the question, answers, and their corresponding numeric values 38 | 39 | driver.quit() 40 | 41 | return items 42 | 43 | 44 | def test_local_perl_site(): 45 | """ 46 | Test upstream site 47 | """ 48 | 49 | items = [] 50 | driver = webdriver.Firefox() 51 | # base_url = "http://www.personal.psu.edu/~j5j/IPIP/ipipneo120.htm" 52 | base_url = "http://localhost/ipipneo120.htm" 53 | driver.get(base_url) 54 | driver.find_element_by_name("Risk").click() 55 | driver.find_element_by_name("Accuracy").click() 56 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() 57 | driver.find_element_by_name("Nick").clear() 58 | driver.find_element_by_name("Nick").send_keys("hello") 59 | driver.find_element_by_name("Sex").click() 60 | driver.find_element_by_name("Age").clear() 61 | driver.find_element_by_name("Age").send_keys("28") 62 | Select(driver.find_element_by_name('Country')).select_by_index(3) 63 | page_source = driver.page_source 64 | d = pq(page_source) 65 | tables = d("table") 66 | main_table = tables[1] # hacky 67 | trs = list(pq(main_table)("tr")) 68 | for tr in trs: 69 | ds = pq(tr) 70 | tds = list(ds("td")) 71 | tds = tds[1:] # skip index number 72 | for td in tds: 73 | text = (" ").join(td.text_content().replace("\n", " ").split()) 74 | radio_button = pq(td)("input") 75 | val = radio_button.val() 76 | items.append([text, val]) 77 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() # go to next 60 questions 78 | time.sleep(3) 79 | page_source = driver.page_source # ATTENTION! 80 | d = pq(page_source) 81 | tables = d("table") 82 | main_table = tables[0] # hacky 83 | trs = list(pq(main_table)("tr")) 84 | for tr in trs: 85 | ds = pq(tr) 86 | tds = list(ds("td")) 87 | tds = tds[1:] # skip index number 88 | for td in tds: 89 | text = (" ").join(td.text_content().replace("\n", " ").split()) 90 | radio_button = pq(td)("input") 91 | val = radio_button.val() 92 | items.append([text, val]) 93 | 94 | driver.quit() 95 | 96 | return items 97 | 98 | 99 | def test_upstream_site(): 100 | """ 101 | Test upstream site 102 | """ 103 | 104 | items = [] 105 | driver = webdriver.Firefox() 106 | base_url = "http://www.personal.psu.edu/~j5j/IPIP/ipipneo120.htm" 107 | driver.get(base_url) 108 | driver.find_element_by_name("Risk").click() 109 | driver.find_element_by_name("Accuracy").click() 110 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() 111 | driver.find_element_by_name("Nick").clear() 112 | driver.find_element_by_name("Nick").send_keys("hello") 113 | driver.find_element_by_name("Sex").click() 114 | driver.find_element_by_name("Age").clear() 115 | driver.find_element_by_name("Age").send_keys("28") 116 | Select(driver.find_element_by_name('Country')).select_by_index(3) 117 | page_source = driver.page_source 118 | d = pq(page_source) 119 | tables = d("table") 120 | main_table = tables[1] # hacky 121 | trs = list(pq(main_table)("tr")) 122 | for tr in trs: 123 | ds = pq(tr) 124 | tds = list(ds("td")) 125 | tds = tds[1:] # skip index number 126 | for td in tds: 127 | text = (" ").join(td.text_content().replace("\n", " ").split()) 128 | radio_button = pq(td)("input") 129 | val = radio_button.val() 130 | items.append([text, val]) 131 | driver.find_element_by_css_selector("input[type=\"submit\"]").click() # go to next 60 questions 132 | time.sleep(3) 133 | page_source = driver.page_source # ATTENTION! 134 | d = pq(page_source) 135 | tables = d("table") 136 | main_table = tables[0] # hacky 137 | trs = list(pq(main_table)("tr")) 138 | for tr in trs: 139 | ds = pq(tr) 140 | tds = list(ds("td")) 141 | tds = tds[1:] # skip index number 142 | for td in tds: 143 | text = (" ").join(td.text_content().replace("\n", " ").split()) 144 | radio_button = pq(td)("input") 145 | val = radio_button.val() 146 | items.append([text, val]) 147 | 148 | driver.quit() 149 | 150 | return items 151 | 152 | """ 153 | debug = True 154 | if debug: 155 | from IPython import embed 156 | embed() 157 | if debug: 158 | time.sleep(3600) 159 | driver.quit() 160 | """ 161 | 162 | 163 | if __name__ == "__main__": 164 | perl_items = test_local_perl_site() 165 | 166 | python_items = test_local_python_site() 167 | 168 | # print(perl_items) 169 | # print(python_items) 170 | 171 | for index, item in enumerate(perl_items): # compare the question, answers, and their corresponding numeric values 172 | if item != python_items[index]: 173 | print(index, item, python_items[index]) 174 | else: 175 | # print("[+] Item <%s> is OK!" % item) 176 | pass 177 | -------------------------------------------------------------------------------- /app/static/css/jquery.jqplot.css: -------------------------------------------------------------------------------- 1 | /*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/ 2 | .jqplot-target { 3 | position: relative; 4 | color: #666666; 5 | font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; 6 | font-size: 1em; 7 | /* height: 300px; 8 | width: 400px;*/ 9 | } 10 | 11 | /*rules applied to all axes*/ 12 | .jqplot-axis { 13 | font-size: 0.75em; 14 | } 15 | 16 | .jqplot-xaxis { 17 | margin-top: 10px; 18 | } 19 | 20 | .jqplot-x2axis { 21 | margin-bottom: 10px; 22 | } 23 | 24 | .jqplot-yaxis { 25 | margin-right: 10px; 26 | } 27 | 28 | .jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis { 29 | margin-left: 10px; 30 | margin-right: 10px; 31 | } 32 | 33 | /*rules applied to all axis tick divs*/ 34 | .jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick { 35 | position: absolute; 36 | white-space: pre; 37 | } 38 | 39 | 40 | .jqplot-xaxis-tick { 41 | top: 0px; 42 | /* initial position untill tick is drawn in proper place */ 43 | left: 15px; 44 | /* padding-top: 10px;*/ 45 | vertical-align: top; 46 | } 47 | 48 | .jqplot-x2axis-tick { 49 | bottom: 0px; 50 | /* initial position untill tick is drawn in proper place */ 51 | left: 15px; 52 | /* padding-bottom: 10px;*/ 53 | vertical-align: bottom; 54 | } 55 | 56 | .jqplot-yaxis-tick { 57 | right: 0px; 58 | /* initial position untill tick is drawn in proper place */ 59 | top: 15px; 60 | /* padding-right: 10px;*/ 61 | text-align: right; 62 | } 63 | 64 | .jqplot-yaxis-tick.jqplot-breakTick { 65 | right: -20px; 66 | margin-right: 0px; 67 | padding:1px 5px 1px 5px; 68 | /*background-color: white;*/ 69 | z-index: 2; 70 | font-size: 1.5em; 71 | } 72 | 73 | .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { 74 | left: 0px; 75 | /* initial position untill tick is drawn in proper place */ 76 | top: 15px; 77 | /* padding-left: 10px;*/ 78 | /* padding-right: 15px;*/ 79 | text-align: left; 80 | } 81 | 82 | .jqplot-yMidAxis-tick { 83 | text-align: center; 84 | white-space: nowrap; 85 | } 86 | 87 | .jqplot-xaxis-label { 88 | margin-top: 10px; 89 | font-size: 11pt; 90 | position: absolute; 91 | } 92 | 93 | .jqplot-x2axis-label { 94 | margin-bottom: 10px; 95 | font-size: 11pt; 96 | position: absolute; 97 | } 98 | 99 | .jqplot-yaxis-label { 100 | margin-right: 10px; 101 | /* text-align: center;*/ 102 | font-size: 11pt; 103 | position: absolute; 104 | } 105 | 106 | .jqplot-yMidAxis-label { 107 | font-size: 11pt; 108 | position: absolute; 109 | } 110 | 111 | .jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label { 112 | /* text-align: center;*/ 113 | font-size: 11pt; 114 | margin-left: 10px; 115 | position: absolute; 116 | } 117 | 118 | .jqplot-meterGauge-tick { 119 | font-size: 0.75em; 120 | color: #999999; 121 | } 122 | 123 | .jqplot-meterGauge-label { 124 | font-size: 1em; 125 | color: #999999; 126 | } 127 | 128 | table.jqplot-table-legend { 129 | margin-top: 12px; 130 | margin-bottom: 12px; 131 | margin-left: 12px; 132 | margin-right: 12px; 133 | } 134 | 135 | table.jqplot-table-legend, table.jqplot-cursor-legend { 136 | background-color: rgba(255,255,255,0.6); 137 | border: 1px solid #cccccc; 138 | position: absolute; 139 | font-size: 0.75em; 140 | } 141 | 142 | td.jqplot-table-legend { 143 | vertical-align:middle; 144 | } 145 | 146 | /* 147 | These rules could be used instead of assigning 148 | element styles and relying on js object properties. 149 | */ 150 | 151 | /* 152 | td.jqplot-table-legend-swatch { 153 | padding-top: 0.5em; 154 | text-align: center; 155 | } 156 | 157 | tr.jqplot-table-legend:first td.jqplot-table-legend-swatch { 158 | padding-top: 0px; 159 | } 160 | */ 161 | 162 | td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { 163 | cursor: pointer; 164 | } 165 | 166 | .jqplot-table-legend .jqplot-series-hidden { 167 | text-decoration: line-through; 168 | } 169 | 170 | div.jqplot-table-legend-swatch-outline { 171 | border: 1px solid #cccccc; 172 | padding:1px; 173 | } 174 | 175 | div.jqplot-table-legend-swatch { 176 | width:0px; 177 | height:0px; 178 | border-top-width: 5px; 179 | border-bottom-width: 5px; 180 | border-left-width: 6px; 181 | border-right-width: 6px; 182 | border-top-style: solid; 183 | border-bottom-style: solid; 184 | border-left-style: solid; 185 | border-right-style: solid; 186 | } 187 | 188 | .jqplot-title { 189 | top: 0px; 190 | left: 0px; 191 | padding-bottom: 0.5em; 192 | font-size: 1.2em; 193 | } 194 | 195 | table.jqplot-cursor-tooltip { 196 | border: 1px solid #cccccc; 197 | font-size: 0.75em; 198 | } 199 | 200 | 201 | .jqplot-cursor-tooltip { 202 | border: 1px solid #cccccc; 203 | font-size: 0.75em; 204 | white-space: nowrap; 205 | background: rgba(208,208,208,0.5); 206 | padding: 1px; 207 | } 208 | 209 | .jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip { 210 | border: 1px solid #cccccc; 211 | font-size: 0.75em; 212 | white-space: nowrap; 213 | background: rgba(208,208,208,0.5); 214 | padding: 1px; 215 | } 216 | 217 | .jqplot-point-label { 218 | font-size: 0.75em; 219 | z-index: 2; 220 | } 221 | 222 | td.jqplot-cursor-legend-swatch { 223 | vertical-align: middle; 224 | text-align: center; 225 | } 226 | 227 | div.jqplot-cursor-legend-swatch { 228 | width: 1.2em; 229 | height: 0.7em; 230 | } 231 | 232 | .jqplot-error { 233 | /* Styles added to the plot target container when there is an error go here.*/ 234 | text-align: center; 235 | } 236 | 237 | .jqplot-error-message { 238 | /* Styling of the custom error message div goes here.*/ 239 | position: relative; 240 | top: 46%; 241 | display: inline-block; 242 | } 243 | 244 | div.jqplot-bubble-label { 245 | font-size: 0.8em; 246 | /* background: rgba(90%, 90%, 90%, 0.15);*/ 247 | padding-left: 2px; 248 | padding-right: 2px; 249 | color: rgb(20%, 20%, 20%); 250 | } 251 | 252 | div.jqplot-bubble-label.jqplot-bubble-label-highlight { 253 | background: rgba(90%, 90%, 90%, 0.7); 254 | } 255 | 256 | div.jqplot-noData-container { 257 | text-align: center; 258 | background-color: rgba(96%, 96%, 96%, 0.3); 259 | } 260 | -------------------------------------------------------------------------------- /app/views/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Short Form for the IPIP-NEO
4 | (International Personality Item Pool 
5 | Representation of the NEO PI-R™) 6 |

7 |

8 | Warning about this 120-Item Version of the IPIP-NEO 9 |

10 | 11 |
    12 |
  • 13 | Thus far, no program failures for the 120-item version of the 14 | IPIP-NEO have been reported for persons who have answered all of 15 | the items. However, recently a number of individuals have reported 16 | that the program tells them they have not checked the two 17 | acknowledgement boxes on this page, even when they have. For some 18 | reason, this may occur with older Web browsers, so if this happens 19 | to you, you might consider trying again with a more recent version 20 | of your Web browser or with a different Web browser. 21 |
  • 22 |
  • 23 | To access the test, you must indicate that you understand 24 | that taking the test does not guarantee receiving results. 25 |
  • 26 |
  • 27 | You indicate this understanding by clicking the checkbox below. 28 |
  • 29 |
30 |
31 | 32 | 33 | 44 | 45 |
34 | 35 | Yes, I understand that responding to all items on this 36 | inventory is time consuming and that technical difficulties 37 | may prevent the results from being displayed. I am responding 38 | to this inventory with the full knowledge of the risk that I 39 | might not receive results. I accept full responsibility and 40 | risk for the time I invest in responding to this 41 | inventory. 42 | 43 |
46 |

47 | If the Program Does Crash... 48 |

49 | ..and you are using an older Web browser, first try using a newer 50 | browser. A number of people have recently reported overcoming 51 | problems simply by using a newer browser. Whatever your problem, I 52 | want to know about it. If you experience any technical difficulties 53 | (items fail to appear on the screen, test does not advance to next 54 | page, Web browser freezes, no narrative report is displayed, etc.) I 55 | encourage you to send an email describing 56 | the problem to me at j5j@psu.edu. 57 | Other persons who may have referred you to this site would 58 | prefer that you report technical difficulties to me rather than to 59 | them. 60 |

61 | Purpose of this On-Line Inventory 62 |

63 |
    64 |
  • 65 | The primary purpose of this on line inventory is to educate the public 66 | about the five factor model 67 | of personality. 68 |
  • 69 |
  • 70 | More specifically, the report explains the likely consequences of 71 | one's standing on five broad personality domains. 72 |
  • 73 |
  • 74 | These broad domains cover normal differences in personality that 75 | should be obvious to people who know you well. 76 |
  • 77 |
  • 78 | Secondarily, this inventory estimates your standing on the 5 79 | broad domains and 30 subdomains of personality. 80 |
  • 81 |
  • 82 | The inventory does not reveal hidden, secret information about 83 | you nor does it assess serious psychological disorders. 84 |
  • 85 |
  • 86 | The report is designed to be objective, not pleasing or 87 | flattering. 88 |
  • 89 |
  • 90 | Measurement error, misunderstandings, carelessness, and 91 | mischievous responding can invalidate the report. 92 |
  • 93 |
  • 94 | If knowledgeable acquaintances disagree with the test results, 95 | then the results are wrong. 96 |
  • 97 |
98 |

99 | Acknowledgment that You Understand the Limitations of the Test 100 | Results 101 |

102 | Before you can access the test, you must endorse the statement 103 | below by clicking the checkbox. 104 | 105 | 106 | 125 | 126 |
107 | 108 | Yes, I understand that the primary purpose of this site is to 109 | educate the public about the five factor model of 110 | personality, and only secondarily, to estimate the 111 | respondent's standing within the five factor model. I 112 | understand that the program that generates the report is 113 | designed to produce estimates that are as accurate as 114 | possible, but that measurement error or improper responding 115 | can produce inaccurate results. If I think I have answered 116 | the items honestly and carefully but my results are 117 | inaccurate or not as pleasing as I would like them to be, I 118 | will have knowledgeable acquaintances evaluate the validity 119 | of the report before contacting Dr. Johnson. If I choose to 120 | critique the test or narrative report after receiving 121 | feedback from knowledgeable acquaintances, I will do so in a 122 | courteous and civil manner. 123 | 124 |
127 |

128 | For Further Information 129 |

130 |
    131 |
  • 132 | The full IPIP contains 2,413 items assembled by Dr. Lewis R. Goldberg. 133 | The URL for Dr. Goldberg's IPIP is http://ipip.ori.org/ 134 | . The IPIP is in the public domain and its items can be freely 135 | downloaded from that site. 136 |
  • 137 |
  • 138 | The IPIP-NEO is not equivalent to the commercial 139 | inventory on which it is based, the NEO PI-R™, authored by 140 | Paul T. Costa, Jr. and Robert R. McCrae. The genuine NEO 141 | PI-R™ (240 items) is considered by many psychologists to be 142 | the best inventory for measuring traits within the Five Factor 143 | Model (FFM) of personality. The NEO PI-R™ is copyrighted by 144 | Psychological Assessment Resources (PAR) in Florida, and can only 145 | be ordered by professionals and used by permission. You can 146 | contact PAR at: 1-800-331-TEST, 147 | or http://www.parinc.com. 148 |
  • 149 |
  • 150 | The scoring and narrative report routines for these items were 151 | created by Dr. John A. Johnson, Professor of Psychology, Penn 152 | State University. 153 |
  • 154 |
  • 155 | Any programmer who wishes to examine the Perl CGI scripts underlying this 156 | inventory, or anyone with further questions may contact John A. Johnson 157 | at j5j@psu.edu. 158 |
  • 159 |
160 |

161 | Acknowledgements 162 |

163 | Dr. Johnson would like to thank Robin Lowenthal for her invaluable 164 | debugging assistance and Thore Harald Hoye for his programming 165 | advice. Neither of these individuals is responsible for any errors 166 | that may remain in the program. 167 |

168 | 169 |

170 | 171 | Clicking this button will take you to the first 60 questions only 172 | if you have acknowledged that you have read the above information, 173 | agree to accept the risks involved in responding to this inventory, 174 | and agree to communicate courteously with the site author. 175 | 176 |
177 |
178 |
179 | %rebase base title="Short Form for the IPIP NEO-PI, Introductory Information" 180 | -------------------------------------------------------------------------------- /app/evaluator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # pylint: disable=C0103,R0912,R0914,R0915 3 | 4 | """ 5 | Personality evaluation logic. 6 | 7 | This version corresponds to IPIPlinux.zip which I got from Dr. John in June 8 | 2021. 9 | 10 | Based on shortipipneo3.cgi 100%. 11 | """ 12 | 13 | import json 14 | import datetime 15 | import collections 16 | 17 | import bottle 18 | 19 | 20 | def evaluate_api(request): 21 | """API endpoint.""" 22 | 23 | # Extract identifying variables 24 | data = request.forms.get 25 | Sex = data('Sex') 26 | Age = int(data('Age')) 27 | Nick = data('Nick') 28 | Country = data('Country') 29 | 30 | # Get the item responses 31 | items = 121 # shortipipneo 32 | Q = [0] * (items) 33 | 34 | for i in range(1, items): 35 | variable = "Q%d" % i 36 | Q[i] = data(variable, 0) 37 | 38 | Q = list(map(int, Q)) 39 | 40 | # Score facet scales 41 | ss = [0] * items 42 | for i in range(1, 31): 43 | k = 0 44 | for _ in range(0, 4): 45 | ss[i] += Q[i + k] 46 | k = k + 30 47 | 48 | # Number each facet set from 1-6 49 | NF = [0] * items 50 | EF = [0] * items 51 | OF = [0] * items 52 | AF = [0] * items 53 | CF = [0] * items 54 | j = 0 55 | for i in range(1, 7): 56 | NF[i] = ss[i + j] 57 | EF[i] = ss[i + j + 1] 58 | OF[i] = ss[i + j + 2] 59 | AF[i] = ss[i + j + 3] 60 | CF[i] = ss[i + j + 4] 61 | j = j + 4 62 | 63 | # Score domain scales 64 | # 1 2 3 4 5 6 65 | N = ss[1] + ss[6] + ss[11] + ss[16] + ss[21] + ss[26] 66 | E = ss[2] + ss[7] + ss[12] + ss[17] + ss[22] + ss[27] 67 | O = ss[3] + ss[8] + ss[13] + ss[18] + ss[23] + ss[28] 68 | A = ss[4] + ss[9] + ss[14] + ss[19] + ss[24] + ss[29] 69 | C = ss[5] + ss[10] + ss[15] + ss[20] + ss[25] + ss[30] 70 | 71 | # Standardize scores 72 | 73 | if Sex == "Male" and Age < 21: 74 | norm = ( 75 | 0, 67.84, 80.70, 85.98, 81.98, 79.66, 15.83, 15.37, 12.37, 14.66, 14.49, 76 | 11.72, 11.93, 10.58, 12.38, 11.67, 9.63, 3.76, 4.41, 4.25, 3.83, 3.25, 3.38, 77 | 13.76, 12.23, 14.06, 11.54, 14.67, 14.41, 3.78, 4.17, 3.66, 3.15, 3.38, 3.68, 78 | 16.68, 14.51, 14.52, 12.84, 15.47, 11.86, 2.96, 3.87, 3.31, 3.16, 3.50, 3.17, 79 | 13.18, 14.85, 15.37, 12.73, 12.01, 13.96, 3.69, 3.44, 3.10, 4.05, 3.94, 3.35, 80 | 15.31, 10.97, 15.22, 13.61, 12.35, 12.08, 2.55, 3.93, 2.92, 3.65, 3.24, 4.02) 81 | Category = "males less than 21 years of age" 82 | 83 | if Sex == "Male" and Age > 20 and Age < 41: 84 | norm = ( 85 | 0, 66.97, 78.90, 86.51, 84.22, 85.50, 16.48, 15.21, 12.65, 13.10, 14.27, 86 | 11.44, 11.75, 10.37, 12.11, 12.18, 9.13, 3.76, 4.30, 4.12, 3.81, 3.52, 3.48, 87 | 13.31, 11.34, 14.58, 12.07, 13.34, 14.30, 3.80, 3.99, 3.58, 3.23, 3.43, 3.53, 88 | 15.94, 14.94, 14.60, 13.14, 16.11, 11.66, 3.18, 3.63, 3.19, 3.39, 3.25, 3.72, 89 | 12.81, 15.93, 15.37, 14.58, 11.43, 13.77, 3.69, 3.18, 2.92, 3.70, 3.57, 3.29, 90 | 15.80, 12.05, 15.68, 15.36, 13.27, 13.31, 2.44, 4.26, 2.76, 3.39, 3.31, 4.03) 91 | Category = "men between 21 and 40 years of age" 92 | 93 | if Sex == "Male" and Age > 40 and Age < 61: 94 | norm = ( 95 | 0, 64.11, 77.06, 83.04, 88.33, 91.27, 16.04, 14.31, 13.05, 11.76, 13.35, 96 | 10.79, 11.60, 9.78, 11.85, 11.24, 8.81, 3.56, 4.16, 3.94, 3.62, 3.55, 3.35, 97 | 13.22, 10.45, 14.95, 12.27, 11.82, 14.32, 3.71, 3.68, 3.44, 3.30, 3.23, 3.29, 98 | 14.65, 14.66, 14.76, 12.69, 15.40, 11.04, 3.35, 3.59, 3.02, 3.44, 3.43, 3.93, 99 | 13.42, 16.94, 15.65, 15.66, 11.96, 14.21, 3.49, 2.83, 2.88, 3.33, 3.34, 3.17, 100 | 16.19, 13.33, 16.56, 16.51, 14.05, 14.60, 2.25, 4.32, 2.50, 2.93, 3.13, 3.78) 101 | Category = "men between 41 and 60 years of age" 102 | 103 | if Sex == "Male" and Age > 60: 104 | norm = ( 105 | 0, 58.42, 79.73, 79.78, 90.20, 95.31, 15.48, 13.63, 12.21, 11.73, 11.99, 106 | 9.81, 11.46, 8.18, 11.08, 9.91, 8.24, 3.54, 4.31, 3.59, 3.82, 3.36, 3.28, 107 | 14.55, 11.19, 15.29, 12.81, 11.03, 15.02, 3.47, 3.58, 3.10, 3.25, 2.88, 3.16, 108 | 14.06, 14.22, 14.34, 12.42, 14.61, 10.11, 3.13, 3.64, 2.90, 3.20, 3.89, 4.02, 109 | 13.96, 17.74, 15.76, 16.18, 11.87, 14.00, 3.13, 2.39, 2.74, 3.41, 3.50, 3.11, 110 | 16.32, 14.41, 17.54, 16.65, 14.98, 15.18, 2.31, 4.49, 2.30, 2.68, 2.76, 3.61) 111 | Category = "men over 60 years of age" 112 | 113 | if Sex == "Female" and Age < 21: 114 | norm = ( 115 | 0, 73.41, 84.26, 89.01, 89.14, 81.27, 15.61, 14.98, 11.84, 13.21, 14.38, 116 | 13.31, 13.09, 11.05, 12.11, 12.48, 11.30, 3.62, 4.18, 4.20, 3.82, 3.30, 3.47, 117 | 14.47, 13.12, 14.03, 12.67, 14.69, 15.34, 3.60, 4.13, 3.68, 3.09, 3.48, 3.42, 118 | 16.86, 15.93, 16.02, 12.95, 15.06, 12.17, 2.89, 3.44, 2.95, 3.24, 3.51, 3.02, 119 | 13.46, 16.11, 16.66, 13.73, 13.23, 15.70, 3.72, 2.94, 2.69, 4.14, 3.79, 2.84, 120 | 15.30, 11.11, 15.62, 14.69, 12.73, 11.82, 2.54, 4.17, 2.76, 3.37, 3.19, 4.01) 121 | 122 | Category = "females less than 21 years of age" 123 | 124 | if Sex == "Female" and Age > 20 and Age < 41: 125 | norm = ( 126 | 0, 72.14, 80.78, 88.25, 91.91, 87.57, 16.16, 14.64, 12.15, 11.39, 13.87, 127 | 13.08, 12.72, 10.79, 12.20, 12.71, 10.69, 3.68, 4.13, 4.07, 3.79, 3.58, 3.64, 128 | 14.05, 11.92, 14.25, 12.77, 12.84, 14.96, 3.66, 4.05, 3.61, 3.24, 3.53, 3.31, 129 | 15.64, 15.97, 16.41, 12.84, 15.28, 12.06, 3.34, 3.30, 2.69, 3.44, 3.47, 3.46, 130 | 13.15, 17.34, 16.81, 15.57, 12.98, 15.52, 3.71, 2.61, 2.53, 3.50, 3.57, 2.87, 131 | 16.02, 12.67, 16.36, 16.11, 13.56, 12.91, 2.34, 4.51, 2.54, 3.05, 3.23, 4.18) 132 | 133 | Category = "women between 21 and 40 years of age" 134 | 135 | if Sex == "Female" and Age > 40 and Age < 61: 136 | norm = ( 137 | 0, 67.38, 78.62, 86.15, 95.73, 93.45, 16.10, 14.19, 12.62, 9.84, 12.94, 138 | 12.05, 11.19, 10.07, 12.07, 11.98, 10.07, 3.72, 4.03, 3.97, 3.73, 3.69, 3.56, 139 | 14.10, 10.84, 14.51, 13.03, 11.08, 15.00, 3.72, 3.86, 3.50, 3.46, 3.42, 3.26, 140 | 14.43, 16.00, 16.37, 12.58, 14.87, 11.85, 3.49, 3.20, 2.58, 3.45, 3.65, 3.74, 141 | 13.79, 18.16, 17.04, 17.02, 13.41, 15.82, 3.52, 2.21, 2.40, 2.88, 3.30, 2.71, 142 | 16.50, 13.68, 17.29, 17.16, 14.35, 14.41, 2.16, 4.51, 2.27, 2.73, 3.13, 3.86) 143 | 144 | Category = "women between 41 and 60 years of age" 145 | 146 | if Sex == "Female" and Age > 60: 147 | norm = ( 148 | 0, 63.48, 78.22, 81.56, 97.17, 96.44, 14.92, 12.73, 12.66, 9.52, 12.43, 149 | 11.39, 10.52, 9.10, 12.00, 10.21, 9.87, 3.61, 3.82, 3.68, 3.61, 3.58, 3.44, 150 | 14.85, 10.93, 14.19, 12.76, 10.08, 15.65, 3.43, 3.70, 3.64, 3.26, 3.20, 3.04, 151 | 13.15, 15.95, 15.73, 11.80, 14.21, 10.81, 3.71, 3.12, 2.74, 3.26, 3.47, 3.89, 152 | 14.19, 18.64, 17.13, 17.98, 13.58, 15.83, 3.39, 1.90, 2.18, 2.56, 3.38, 2.85, 153 | 16.50, 15.15, 18.34, 17.19, 14.70, 15.11, 2.24, 4.07, 1.81, 2.49, 3.15, 3.66) 154 | 155 | Category = "women over 60 years of age" 156 | 157 | SN = (10 * (N - norm[1]) / norm[6]) + 50 158 | SE = (10 * (E - norm[2]) / norm[7]) + 50 159 | SO = (10 * (O - norm[3]) / norm[8]) + 50 160 | SA = (10 * (A - norm[4]) / norm[9]) + 50 161 | SC = (10 * (C - norm[5]) / norm[10]) + 50 162 | 163 | SNF = [0] * items 164 | SEF = [0] * items 165 | SOF = [0] * items 166 | SAF = [0] * items 167 | SCF = [0] * items 168 | 169 | for i in range(1, 7): 170 | SNF[i] = 50 + (10 * (NF[i] - norm[i + 10]) / norm[i + 16]) 171 | SEF[i] = 50 + (10 * (EF[i] - norm[i + 22]) / norm[i + 28]) 172 | SOF[i] = 50 + (10 * (OF[i] - norm[i + 34]) / norm[i + 40]) 173 | SAF[i] = 50 + (10 * (AF[i] - norm[i + 46]) / norm[i + 52]) 174 | SCF[i] = 50 + (10 * (CF[i] - norm[i + 58]) / norm[i + 64]) 175 | 176 | # Cubic approximations for percentiles 177 | 178 | CONST1 = 210.335958661391 179 | CONST2 = 16.7379362643389 180 | CONST3 = 0.405936512733332 181 | CONST4 = 0.00270624341822222 182 | 183 | SNP = int(CONST1 - (CONST2 * SN) + (CONST3 * SN ** 2) - (CONST4 * SN ** 3)) 184 | SEP = int(CONST1 - (CONST2 * SE) + (CONST3 * SE ** 2) - (CONST4 * SE ** 3)) 185 | SOP = int(CONST1 - (CONST2 * SO) + (CONST3 * SO ** 2) - (CONST4 * SO ** 3)) 186 | SAP = int(CONST1 - (CONST2 * SA) + (CONST3 * SA ** 2) - (CONST4 * SA ** 3)) 187 | SCP = int(CONST1 - (CONST2 * SC) + (CONST3 * SC ** 2) - (CONST4 * SC ** 3)) 188 | 189 | if SN < 32: 190 | SNP = 1 191 | if SE < 32: 192 | SEP = 1 193 | if SO < 32: 194 | SOP = 1 195 | if SA < 32: 196 | SAP = 1 197 | if SC < 32: 198 | SCP = 1 199 | 200 | if SN > 73: 201 | SNP = 99 202 | if SE > 73: 203 | SEP = 99 204 | if SO > 73: 205 | SOP = 99 206 | if SA > 73: 207 | SAP = 99 208 | if SC > 73: 209 | SCP = 99 210 | 211 | # Create percentile scores and low, average, high labels for facets 212 | SNFP = [0] * items 213 | SEFP = [0] * items 214 | SOFP = [0] * items 215 | SAFP = [0] * items 216 | SCFP = [0] * items 217 | 218 | flev = [0] * items 219 | for i in range(1, 7): 220 | flev[i] = SNF[i] 221 | if SNF[i] < 45: 222 | flev[i] = "low" 223 | 224 | if SNF[i] >= 45 and SNF[i] <= 55: 225 | flev[i] = "average" 226 | 227 | if SNF[i] > 55: 228 | flev[i] = "high" 229 | 230 | SNFP[i] = int(CONST1 - (CONST2 * SNF[i]) + (CONST3 * SNF[i] ** 2) - 231 | (CONST4 * SNF[i] ** 3)) 232 | 233 | if SNF[i] < 32: 234 | SNFP[i] = 1 235 | 236 | if SNF[i] > 73: 237 | SNFP[i] = 99 238 | 239 | for i in range(1, 7): 240 | flev[i + 6] = SEF[i] 241 | if SEF[i] < 45: 242 | flev[i + 6] = "low" 243 | 244 | if SEF[i] >= 45 and SEF[i] <= 55: 245 | flev[i + 6] = "average" 246 | 247 | if SEF[i] > 55: 248 | flev[i + 6] = "high" 249 | 250 | SEFP[i] = int(CONST1 - (CONST2 * SEF[i]) + (CONST3 * SEF[i] ** 2) - 251 | (CONST4 * SEF[i] ** 3)) 252 | 253 | if SEF[i] < 32: 254 | SEFP[i] = 1 255 | if SEF[i] > 73: 256 | SEFP[i] = 99 257 | 258 | for i in range(1, 7): 259 | flev[i + 12] = SOF[i] 260 | if SOF[i] < 45: 261 | flev[i + 12] = "low" 262 | 263 | if SOF[i] >= 45 and SOF[i] <= 55: 264 | flev[i + 12] = "average" 265 | 266 | if SOF[i] > 55: 267 | flev[i + 12] = "high" 268 | 269 | SOFP[i] = int(CONST1 - (CONST2 * SOF[i]) + (CONST3 * SOF[i] ** 2) - 270 | (CONST4 * SOF[i] ** 3)) 271 | 272 | if SOF[i] < 32: 273 | SOFP[i] = 1 274 | if SOF[i] > 73: 275 | SOFP[i] = 99 276 | 277 | for i in range(1, 7): 278 | flev[i + 18] = SAF[i] 279 | if SAF[i] < 45: 280 | flev[i + 18] = "low" 281 | 282 | if SAF[i] >= 45 and SAF[i] <= 55: 283 | flev[i + 18] = "average" 284 | 285 | if SAF[i] > 55: 286 | flev[i + 18] = "high" 287 | 288 | SAFP[i] = int(CONST1 - (CONST2 * SAF[i]) + (CONST3 * SAF[i] ** 2) - 289 | (CONST4 * SAF[i] ** 3)) 290 | 291 | if SAF[i] < 32: 292 | SAFP[i] = 1 293 | if SAF[i] > 73: 294 | SAFP[i] = 99 295 | 296 | for i in range(1, 7): 297 | flev[i + 24] = SCF[i] 298 | if SCF[i] < 45: 299 | flev[i + 24] = "low" 300 | if SCF[i] >= 45 and SCF[i] <= 55: 301 | flev[i + 24] = "average" 302 | if SCF[i] > 55: 303 | flev[i + 24] = "high" 304 | 305 | SCFP[i] = int(CONST1 - (CONST2 * SCF[i]) + (CONST3 * SCF[i] ** 2) - 306 | (CONST4 * SCF[i] ** 3)) 307 | 308 | if SCF[i] < 32: 309 | SCFP[i] = 1 310 | if SCF[i] > 73: 311 | SCFP[i] = 99 312 | 313 | LO = 45 314 | HI = 55 315 | 316 | if "results_api" not in request.url: # hack 317 | return SEP, SEFP, LO, HI, SE, SAP, SAFP, SA, SC, SCP, SCFP, flev, SOP, \ 318 | SOFP, SO, Nick, Country, SNP, SNFP, Category, SN, Sex, Age, Q 319 | else: # treat as an api call. 320 | m = {} 321 | 322 | labels = ['EXTRAVERSION', 'Friendliness', 'Gregariousness', 'Assertiveness', 'Activity Level', 'Excitement-Seeking', 'Cheerfulness'] 323 | m[labels[0]] = SEP 324 | for i in range(1, len(labels)): 325 | m[labels[i]] = SEFP[i] 326 | 327 | labels = ['AGREEABLENESS', 'Trust', 'Morality', 'Altruism', 'Cooperation', 'Modesty', 'Sympathy'] 328 | m[labels[0]] = SAP 329 | for i in range(1, len(labels)): 330 | m[labels[i]] = SAFP[i] 331 | 332 | labels = ['CONSCIENTIOUSNESS', 'Self-Efficacy', 'Orderliness', 'Dutifulness', 'Achievement-Striving', 'Self-Discipline', 'Cautiousness'] 333 | m[labels[0]] = SCP 334 | for i in range(1, len(labels)): 335 | m[labels[i]] = SCFP[i] 336 | 337 | labels = ['NEUROTICISM', 'Anxiety', 'Anger', 'Depression', 'Self-Consciousness', 'Immoderation', 'Vulnerability'] 338 | m[labels[0]] = SNP 339 | for i in range(1, len(labels)): 340 | m[labels[i]] = SNFP[i] 341 | 342 | labels = ['OPENNESS', 'Imagination', 'Artistic Interests', 'Emotionality', 'Adventurousness', 'Intellect', 'Liberalism'] 343 | m[labels[0]] = SOP 344 | for i in range(1, len(labels)): 345 | m[labels[i]] = SOFP[i] 346 | 347 | # od = collections.OrderedDict(sorted(m.items())) 348 | return json.dumps(m) 349 | 350 | 351 | def evaluate(request, db=None): 352 | 353 | """Personality evaluation logic.""" 354 | 355 | SEP, SEFP, LO, HI, SE, SAP, SAFP, SA, SC, SCP, SCFP, flev, SOP, SOFP, SO, \ 356 | Nick, Country, SNP, SNFP, Category, SN, Sex, Age, Q = evaluate_api(request) 357 | 358 | # Check sex and age 359 | if Sex != "Male" and Sex != "Female": 360 | return """You did not indicate your sex at the beginning of the 361 | inventory. Your answers cannot be normed properly unless you indicate 362 | whether you are male or female. Please return to the inventory and indicate 363 | your sex.""" 364 | 365 | if Age < 10: 366 | return """You did not indicate how old you are at the beginning of the 367 | inventory, or you typed in an age that is too young. Your answers cannot be 368 | normed properly unless type in a valid age. Please return to the inventory 369 | and change your response.""" 370 | 371 | # Save Data 372 | if db: 373 | responses = " ".join([str(i) for i in Q[1:121]]) 374 | 375 | db.execute('insert into RESULTS values(?, ?, ?, ?, ?, ?)', 376 | (datetime.datetime.now(), Sex, Age, Nick, Country, 377 | responses)) 378 | db.commit() 379 | 380 | return bottle.template( 381 | 'results', SEP=SEP, SEFP=SEFP, 382 | LO=45, HI=55, SE=SE, SAP=SAP, SAFP=SAFP, SA=SA, 383 | SC=SC, SCP=SCP, SCFP=SCFP, flev=flev, 384 | SOP=SOP, SOFP=SOFP, 385 | SO=SO, Nick=Nick, Country=Country, 386 | SNP=SNP, SNFP=SNFP, Category=Category, 387 | SN=SN) 388 | -------------------------------------------------------------------------------- /app/static/js/plugins/jqplot.pointLabels.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jqPlot 3 | * Pure JavaScript plotting plugin using jQuery 4 | * 5 | * Version: 1.0.9 6 | * Revision: d96a669 7 | * 8 | * Copyright (c) 2009-2016 Chris Leonello 9 | * jqPlot is currently available for use in all personal or commercial projects 10 | * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL 11 | * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can 12 | * choose the license that best suits your project and use it accordingly. 13 | * 14 | * Although not required, the author would appreciate an email letting him 15 | * know of any substantial use of jqPlot. You can reach the author at: 16 | * chris at jqplot dot com or see http://www.jqplot.com/info.php . 17 | * 18 | * If you are feeling kind and generous, consider supporting the project by 19 | * making a donation at: http://www.jqplot.com/donate.php . 20 | * 21 | * sprintf functions contained in jqplot.sprintf.js by Ash Searle: 22 | * 23 | * version 2007.04.27 24 | * author Ash Searle 25 | * http://hexmen.com/blog/2007/03/printf-sprintf/ 26 | * http://hexmen.com/js/sprintf.js 27 | * The author (Ash Searle) has placed this code in the public domain: 28 | * "This code is unrestricted: you are free to use it however you like." 29 | * 30 | */ 31 | (function($) { 32 | 33 | /** 34 | * Class: $.jqplot.PointLabels 35 | * Plugin for putting labels at the data points. 36 | * 37 | * To use this plugin, include the js 38 | * file in your source: 39 | * 40 | * > 41 | * 42 | * By default, the last value in the data ponit array in the data series is used 43 | * for the label. For most series renderers, extra data can be added to the 44 | * data point arrays and the last value will be used as the label. 45 | * 46 | * For instance, 47 | * this series: 48 | * 49 | * > [[1,4], [3,5], [7,2]] 50 | * 51 | * Would, by default, use the y values in the labels. 52 | * Extra data can be added to the series like so: 53 | * 54 | * > [[1,4,'mid'], [3 5,'hi'], [7,2,'low']] 55 | * 56 | * And now the point labels would be 'mid', 'low', and 'hi'. 57 | * 58 | * Options to the point labels and a custom labels array can be passed into the 59 | * "pointLabels" option on the series option like so: 60 | * 61 | * > series:[{pointLabels:{ 62 | * > labels:['mid', 'hi', 'low'], 63 | * > location:'se', 64 | * > ypadding: 12 65 | * > } 66 | * > }] 67 | * 68 | * A custom labels array in the options takes precendence over any labels 69 | * in the series data. If you have a custom labels array in the options, 70 | * but still want to use values from the series array as labels, set the 71 | * "labelsFromSeries" option to true. 72 | * 73 | * By default, html entities (<, >, etc.) are escaped in point labels. 74 | * If you want to include actual html markup in the labels, 75 | * set the "escapeHTML" option to false. 76 | * 77 | */ 78 | $.jqplot.PointLabels = function(options) { 79 | // Group: Properties 80 | // 81 | // prop: show 82 | // show the labels or not. 83 | this.show = $.jqplot.config.enablePlugins; 84 | // prop: location 85 | // compass location where to position the label around the point. 86 | // 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' 87 | this.location = 'n'; 88 | // prop: labelsFromSeries 89 | // true to use labels within data point arrays. 90 | this.labelsFromSeries = false; 91 | // prop: seriesLabelIndex 92 | // array index for location of labels within data point arrays. 93 | // if null, will use the last element of the data point array. 94 | this.seriesLabelIndex = null; 95 | // prop: labels 96 | // array of arrays of labels, one array for each series. 97 | this.labels = []; 98 | // actual labels that will get displayed. 99 | // needed to preserve user specified labels in labels array. 100 | this._labels = []; 101 | // prop: stackedValue 102 | // true to display value as stacked in a stacked plot. 103 | // no effect if labels is specified. 104 | this.stackedValue = false; 105 | // prop: ypadding 106 | // vertical padding in pixels between point and label 107 | this.ypadding = 6; 108 | // prop: xpadding 109 | // horizontal padding in pixels between point and label 110 | this.xpadding = 6; 111 | // prop: escapeHTML 112 | // true to escape html entities in the labels. 113 | // If you want to include markup in the labels, set to false. 114 | this.escapeHTML = true; 115 | // prop: edgeTolerance 116 | // Number of pixels that the label must be away from an axis 117 | // boundary in order to be drawn. Negative values will allow overlap 118 | // with the grid boundaries. 119 | this.edgeTolerance = -5; 120 | // prop: formatter 121 | // A class of a formatter for the tick text. sprintf by default. 122 | this.formatter = $.jqplot.DefaultTickFormatter; 123 | // prop: formatString 124 | // string passed to the formatter. 125 | this.formatString = ''; 126 | // prop: hideZeros 127 | // true to not show a label for a value which is 0. 128 | this.hideZeros = false; 129 | this._elems = []; 130 | 131 | $.extend(true, this, options); 132 | }; 133 | 134 | var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w']; 135 | var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7}; 136 | var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e']; 137 | 138 | // called with scope of a series 139 | $.jqplot.PointLabels.init = function (target, data, seriesDefaults, opts, plot){ 140 | var options = $.extend(true, {}, seriesDefaults, opts); 141 | options.pointLabels = options.pointLabels || {}; 142 | if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal' && !options.pointLabels.location) { 143 | options.pointLabels.location = 'e'; 144 | } 145 | // add a pointLabels attribute to the series plugins 146 | this.plugins.pointLabels = new $.jqplot.PointLabels(options.pointLabels); 147 | this.plugins.pointLabels.setLabels.call(this); 148 | }; 149 | 150 | // called with scope of series 151 | $.jqplot.PointLabels.prototype.setLabels = function() { 152 | var p = this.plugins.pointLabels; 153 | var labelIdx; 154 | if (p.seriesLabelIndex != null) { 155 | labelIdx = p.seriesLabelIndex; 156 | } 157 | else if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal') { 158 | labelIdx = (this._plotData[0].length < 3) ? 0 : this._plotData[0].length -1; 159 | } 160 | else { 161 | labelIdx = (this._plotData.length === 0) ? 0 : this._plotData[0].length -1; 162 | } 163 | p._labels = []; 164 | if (p.labels.length === 0 || p.labelsFromSeries) { 165 | if (p.stackedValue) { 166 | if (this._plotData.length && this._plotData[0].length){ 167 | // var idx = p.seriesLabelIndex || this._plotData[0].length -1; 168 | for (var i=0; i scr || elb + et > scb) { 360 | elem.remove(); 361 | } 362 | 363 | elem = null; 364 | helem = null; 365 | } 366 | 367 | // finally, animate them if the series is animated 368 | // if (this.renderer.animation && this.renderer.animation._supported && this.renderer.animation.show && plot._drawCount < 2) { 369 | // var sel = '.jqplot-point-label.jqplot-series-'+this.index; 370 | // $(sel).hide(); 371 | // $(sel).fadeIn(1000); 372 | // } 373 | 374 | } 375 | }; 376 | 377 | $.jqplot.postSeriesInitHooks.push($.jqplot.PointLabels.init); 378 | $.jqplot.postDrawSeriesHooks.push($.jqplot.PointLabels.draw); 379 | })(jQuery); 380 | -------------------------------------------------------------------------------- /app/static/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /app/static/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | .btn-default, 7 | .btn-primary, 8 | .btn-success, 9 | .btn-info, 10 | .btn-warning, 11 | .btn-danger { 12 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 13 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 14 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | } 16 | .btn-default:active, 17 | .btn-primary:active, 18 | .btn-success:active, 19 | .btn-info:active, 20 | .btn-warning:active, 21 | .btn-danger:active, 22 | .btn-default.active, 23 | .btn-primary.active, 24 | .btn-success.active, 25 | .btn-info.active, 26 | .btn-warning.active, 27 | .btn-danger.active { 28 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 29 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | } 31 | .btn-default.disabled, 32 | .btn-primary.disabled, 33 | .btn-success.disabled, 34 | .btn-info.disabled, 35 | .btn-warning.disabled, 36 | .btn-danger.disabled, 37 | .btn-default[disabled], 38 | .btn-primary[disabled], 39 | .btn-success[disabled], 40 | .btn-info[disabled], 41 | .btn-warning[disabled], 42 | .btn-danger[disabled], 43 | fieldset[disabled] .btn-default, 44 | fieldset[disabled] .btn-primary, 45 | fieldset[disabled] .btn-success, 46 | fieldset[disabled] .btn-info, 47 | fieldset[disabled] .btn-warning, 48 | fieldset[disabled] .btn-danger { 49 | -webkit-box-shadow: none; 50 | box-shadow: none; 51 | } 52 | .btn-default .badge, 53 | .btn-primary .badge, 54 | .btn-success .badge, 55 | .btn-info .badge, 56 | .btn-warning .badge, 57 | .btn-danger .badge { 58 | text-shadow: none; 59 | } 60 | .btn:active, 61 | .btn.active { 62 | background-image: none; 63 | } 64 | .btn-default { 65 | text-shadow: 0 1px 0 #fff; 66 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 67 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 68 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 69 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 70 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 71 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 72 | background-repeat: repeat-x; 73 | border-color: #dbdbdb; 74 | border-color: #ccc; 75 | } 76 | .btn-default:hover, 77 | .btn-default:focus { 78 | background-color: #e0e0e0; 79 | background-position: 0 -15px; 80 | } 81 | .btn-default:active, 82 | .btn-default.active { 83 | background-color: #e0e0e0; 84 | border-color: #dbdbdb; 85 | } 86 | .btn-default.disabled, 87 | .btn-default[disabled], 88 | fieldset[disabled] .btn-default, 89 | .btn-default.disabled:hover, 90 | .btn-default[disabled]:hover, 91 | fieldset[disabled] .btn-default:hover, 92 | .btn-default.disabled:focus, 93 | .btn-default[disabled]:focus, 94 | fieldset[disabled] .btn-default:focus, 95 | .btn-default.disabled.focus, 96 | .btn-default[disabled].focus, 97 | fieldset[disabled] .btn-default.focus, 98 | .btn-default.disabled:active, 99 | .btn-default[disabled]:active, 100 | fieldset[disabled] .btn-default:active, 101 | .btn-default.disabled.active, 102 | .btn-default[disabled].active, 103 | fieldset[disabled] .btn-default.active { 104 | background-color: #e0e0e0; 105 | background-image: none; 106 | } 107 | .btn-primary { 108 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); 109 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); 110 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); 111 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); 112 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); 113 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 114 | background-repeat: repeat-x; 115 | border-color: #245580; 116 | } 117 | .btn-primary:hover, 118 | .btn-primary:focus { 119 | background-color: #265a88; 120 | background-position: 0 -15px; 121 | } 122 | .btn-primary:active, 123 | .btn-primary.active { 124 | background-color: #265a88; 125 | border-color: #245580; 126 | } 127 | .btn-primary.disabled, 128 | .btn-primary[disabled], 129 | fieldset[disabled] .btn-primary, 130 | .btn-primary.disabled:hover, 131 | .btn-primary[disabled]:hover, 132 | fieldset[disabled] .btn-primary:hover, 133 | .btn-primary.disabled:focus, 134 | .btn-primary[disabled]:focus, 135 | fieldset[disabled] .btn-primary:focus, 136 | .btn-primary.disabled.focus, 137 | .btn-primary[disabled].focus, 138 | fieldset[disabled] .btn-primary.focus, 139 | .btn-primary.disabled:active, 140 | .btn-primary[disabled]:active, 141 | fieldset[disabled] .btn-primary:active, 142 | .btn-primary.disabled.active, 143 | .btn-primary[disabled].active, 144 | fieldset[disabled] .btn-primary.active { 145 | background-color: #265a88; 146 | background-image: none; 147 | } 148 | .btn-success { 149 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 150 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 151 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 152 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 153 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 154 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 155 | background-repeat: repeat-x; 156 | border-color: #3e8f3e; 157 | } 158 | .btn-success:hover, 159 | .btn-success:focus { 160 | background-color: #419641; 161 | background-position: 0 -15px; 162 | } 163 | .btn-success:active, 164 | .btn-success.active { 165 | background-color: #419641; 166 | border-color: #3e8f3e; 167 | } 168 | .btn-success.disabled, 169 | .btn-success[disabled], 170 | fieldset[disabled] .btn-success, 171 | .btn-success.disabled:hover, 172 | .btn-success[disabled]:hover, 173 | fieldset[disabled] .btn-success:hover, 174 | .btn-success.disabled:focus, 175 | .btn-success[disabled]:focus, 176 | fieldset[disabled] .btn-success:focus, 177 | .btn-success.disabled.focus, 178 | .btn-success[disabled].focus, 179 | fieldset[disabled] .btn-success.focus, 180 | .btn-success.disabled:active, 181 | .btn-success[disabled]:active, 182 | fieldset[disabled] .btn-success:active, 183 | .btn-success.disabled.active, 184 | .btn-success[disabled].active, 185 | fieldset[disabled] .btn-success.active { 186 | background-color: #419641; 187 | background-image: none; 188 | } 189 | .btn-info { 190 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 191 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 192 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 193 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 194 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 195 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 196 | background-repeat: repeat-x; 197 | border-color: #28a4c9; 198 | } 199 | .btn-info:hover, 200 | .btn-info:focus { 201 | background-color: #2aabd2; 202 | background-position: 0 -15px; 203 | } 204 | .btn-info:active, 205 | .btn-info.active { 206 | background-color: #2aabd2; 207 | border-color: #28a4c9; 208 | } 209 | .btn-info.disabled, 210 | .btn-info[disabled], 211 | fieldset[disabled] .btn-info, 212 | .btn-info.disabled:hover, 213 | .btn-info[disabled]:hover, 214 | fieldset[disabled] .btn-info:hover, 215 | .btn-info.disabled:focus, 216 | .btn-info[disabled]:focus, 217 | fieldset[disabled] .btn-info:focus, 218 | .btn-info.disabled.focus, 219 | .btn-info[disabled].focus, 220 | fieldset[disabled] .btn-info.focus, 221 | .btn-info.disabled:active, 222 | .btn-info[disabled]:active, 223 | fieldset[disabled] .btn-info:active, 224 | .btn-info.disabled.active, 225 | .btn-info[disabled].active, 226 | fieldset[disabled] .btn-info.active { 227 | background-color: #2aabd2; 228 | background-image: none; 229 | } 230 | .btn-warning { 231 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 232 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 233 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 234 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 235 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 236 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 237 | background-repeat: repeat-x; 238 | border-color: #e38d13; 239 | } 240 | .btn-warning:hover, 241 | .btn-warning:focus { 242 | background-color: #eb9316; 243 | background-position: 0 -15px; 244 | } 245 | .btn-warning:active, 246 | .btn-warning.active { 247 | background-color: #eb9316; 248 | border-color: #e38d13; 249 | } 250 | .btn-warning.disabled, 251 | .btn-warning[disabled], 252 | fieldset[disabled] .btn-warning, 253 | .btn-warning.disabled:hover, 254 | .btn-warning[disabled]:hover, 255 | fieldset[disabled] .btn-warning:hover, 256 | .btn-warning.disabled:focus, 257 | .btn-warning[disabled]:focus, 258 | fieldset[disabled] .btn-warning:focus, 259 | .btn-warning.disabled.focus, 260 | .btn-warning[disabled].focus, 261 | fieldset[disabled] .btn-warning.focus, 262 | .btn-warning.disabled:active, 263 | .btn-warning[disabled]:active, 264 | fieldset[disabled] .btn-warning:active, 265 | .btn-warning.disabled.active, 266 | .btn-warning[disabled].active, 267 | fieldset[disabled] .btn-warning.active { 268 | background-color: #eb9316; 269 | background-image: none; 270 | } 271 | .btn-danger { 272 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 273 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 274 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 275 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 276 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 277 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 278 | background-repeat: repeat-x; 279 | border-color: #b92c28; 280 | } 281 | .btn-danger:hover, 282 | .btn-danger:focus { 283 | background-color: #c12e2a; 284 | background-position: 0 -15px; 285 | } 286 | .btn-danger:active, 287 | .btn-danger.active { 288 | background-color: #c12e2a; 289 | border-color: #b92c28; 290 | } 291 | .btn-danger.disabled, 292 | .btn-danger[disabled], 293 | fieldset[disabled] .btn-danger, 294 | .btn-danger.disabled:hover, 295 | .btn-danger[disabled]:hover, 296 | fieldset[disabled] .btn-danger:hover, 297 | .btn-danger.disabled:focus, 298 | .btn-danger[disabled]:focus, 299 | fieldset[disabled] .btn-danger:focus, 300 | .btn-danger.disabled.focus, 301 | .btn-danger[disabled].focus, 302 | fieldset[disabled] .btn-danger.focus, 303 | .btn-danger.disabled:active, 304 | .btn-danger[disabled]:active, 305 | fieldset[disabled] .btn-danger:active, 306 | .btn-danger.disabled.active, 307 | .btn-danger[disabled].active, 308 | fieldset[disabled] .btn-danger.active { 309 | background-color: #c12e2a; 310 | background-image: none; 311 | } 312 | .thumbnail, 313 | .img-thumbnail { 314 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 315 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 316 | } 317 | .dropdown-menu > li > a:hover, 318 | .dropdown-menu > li > a:focus { 319 | background-color: #e8e8e8; 320 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 321 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 322 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 323 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 324 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 325 | background-repeat: repeat-x; 326 | } 327 | .dropdown-menu > .active > a, 328 | .dropdown-menu > .active > a:hover, 329 | .dropdown-menu > .active > a:focus { 330 | background-color: #2e6da4; 331 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 332 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 333 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 334 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 335 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 336 | background-repeat: repeat-x; 337 | } 338 | .navbar-default { 339 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 340 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 341 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 342 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 343 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 344 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 345 | background-repeat: repeat-x; 346 | border-radius: 4px; 347 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 348 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 349 | } 350 | .navbar-default .navbar-nav > .open > a, 351 | .navbar-default .navbar-nav > .active > a { 352 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 353 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 354 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 355 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 356 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 357 | background-repeat: repeat-x; 358 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 359 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 360 | } 361 | .navbar-brand, 362 | .navbar-nav > li > a { 363 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 364 | } 365 | .navbar-inverse { 366 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 367 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 368 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 369 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 370 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 371 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 372 | background-repeat: repeat-x; 373 | border-radius: 4px; 374 | } 375 | .navbar-inverse .navbar-nav > .open > a, 376 | .navbar-inverse .navbar-nav > .active > a { 377 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 378 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 379 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 380 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 381 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 382 | background-repeat: repeat-x; 383 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 384 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 385 | } 386 | .navbar-inverse .navbar-brand, 387 | .navbar-inverse .navbar-nav > li > a { 388 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 389 | } 390 | .navbar-static-top, 391 | .navbar-fixed-top, 392 | .navbar-fixed-bottom { 393 | border-radius: 0; 394 | } 395 | @media (max-width: 767px) { 396 | .navbar .navbar-nav .open .dropdown-menu > .active > a, 397 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, 398 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { 399 | color: #fff; 400 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 401 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 403 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 405 | background-repeat: repeat-x; 406 | } 407 | } 408 | .alert { 409 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 410 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 411 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 412 | } 413 | .alert-success { 414 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 415 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 416 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 417 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 418 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 419 | background-repeat: repeat-x; 420 | border-color: #b2dba1; 421 | } 422 | .alert-info { 423 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 424 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 425 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 426 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 427 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 428 | background-repeat: repeat-x; 429 | border-color: #9acfea; 430 | } 431 | .alert-warning { 432 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 433 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 435 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 437 | background-repeat: repeat-x; 438 | border-color: #f5e79e; 439 | } 440 | .alert-danger { 441 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 442 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 443 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 444 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 445 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 446 | background-repeat: repeat-x; 447 | border-color: #dca7a7; 448 | } 449 | .progress { 450 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 451 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 452 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 453 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 454 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 455 | background-repeat: repeat-x; 456 | } 457 | .progress-bar { 458 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); 459 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); 460 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); 461 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); 462 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); 463 | background-repeat: repeat-x; 464 | } 465 | .progress-bar-success { 466 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 467 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 468 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 469 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 470 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 471 | background-repeat: repeat-x; 472 | } 473 | .progress-bar-info { 474 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 475 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 476 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 477 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 478 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 479 | background-repeat: repeat-x; 480 | } 481 | .progress-bar-warning { 482 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 483 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 484 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 485 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 486 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 487 | background-repeat: repeat-x; 488 | } 489 | .progress-bar-danger { 490 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 491 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 492 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 493 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 494 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 495 | background-repeat: repeat-x; 496 | } 497 | .progress-bar-striped { 498 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 499 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 500 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 501 | } 502 | .list-group { 503 | border-radius: 4px; 504 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 505 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 506 | } 507 | .list-group-item.active, 508 | .list-group-item.active:hover, 509 | .list-group-item.active:focus { 510 | text-shadow: 0 -1px 0 #286090; 511 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); 512 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); 513 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); 514 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); 515 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); 516 | background-repeat: repeat-x; 517 | border-color: #2b669a; 518 | } 519 | .list-group-item.active .badge, 520 | .list-group-item.active:hover .badge, 521 | .list-group-item.active:focus .badge { 522 | text-shadow: none; 523 | } 524 | .panel { 525 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 526 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 527 | } 528 | .panel-default > .panel-heading { 529 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 530 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 531 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 532 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 533 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 534 | background-repeat: repeat-x; 535 | } 536 | .panel-primary > .panel-heading { 537 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 538 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 539 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 540 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 541 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 542 | background-repeat: repeat-x; 543 | } 544 | .panel-success > .panel-heading { 545 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 546 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 547 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 548 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 549 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 550 | background-repeat: repeat-x; 551 | } 552 | .panel-info > .panel-heading { 553 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 554 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 555 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 556 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 557 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 558 | background-repeat: repeat-x; 559 | } 560 | .panel-warning > .panel-heading { 561 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 562 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 563 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 564 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 565 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 566 | background-repeat: repeat-x; 567 | } 568 | .panel-danger > .panel-heading { 569 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 570 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 571 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 572 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 573 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 574 | background-repeat: repeat-x; 575 | } 576 | .well { 577 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 578 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 579 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 580 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 581 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 582 | background-repeat: repeat-x; 583 | border-color: #dcdcdc; 584 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 585 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 586 | } 587 | /*# sourceMappingURL=bootstrap-theme.css.map */ 588 | -------------------------------------------------------------------------------- /app/static/js/plugins/jqplot.categoryAxisRenderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jqPlot 3 | * Pure JavaScript plotting plugin using jQuery 4 | * 5 | * Version: 1.0.9 6 | * Revision: d96a669 7 | * 8 | * Copyright (c) 2009-2016 Chris Leonello 9 | * jqPlot is currently available for use in all personal or commercial projects 10 | * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL 11 | * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can 12 | * choose the license that best suits your project and use it accordingly. 13 | * 14 | * Although not required, the author would appreciate an email letting him 15 | * know of any substantial use of jqPlot. You can reach the author at: 16 | * chris at jqplot dot com or see http://www.jqplot.com/info.php . 17 | * 18 | * If you are feeling kind and generous, consider supporting the project by 19 | * making a donation at: http://www.jqplot.com/donate.php . 20 | * 21 | * sprintf functions contained in jqplot.sprintf.js by Ash Searle: 22 | * 23 | * version 2007.04.27 24 | * author Ash Searle 25 | * http://hexmen.com/blog/2007/03/printf-sprintf/ 26 | * http://hexmen.com/js/sprintf.js 27 | * The author (Ash Searle) has placed this code in the public domain: 28 | * "This code is unrestricted: you are free to use it however you like." 29 | * 30 | */ 31 | (function($) { 32 | /** 33 | * class: $.jqplot.CategoryAxisRenderer 34 | * A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series. 35 | * 36 | * To use this renderer, include the plugin in your source 37 | * > 38 | * 39 | * and supply the appropriate options to your plot 40 | * 41 | * > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}} 42 | **/ 43 | $.jqplot.CategoryAxisRenderer = function(options) { 44 | $.jqplot.LinearAxisRenderer.call(this); 45 | // prop: sortMergedLabels 46 | // True to sort tick labels when labels are created by merging 47 | // x axis values from multiple series. That is, say you have 48 | // two series like: 49 | // > line1 = [[2006, 4], [2008, 9], [2009, 16]]; 50 | // > line2 = [[2006, 3], [2007, 7], [2008, 6]]; 51 | // If no label array is specified, tick labels will be collected 52 | // from the x values of the series. With sortMergedLabels 53 | // set to true, tick labels will be: 54 | // > [2006, 2007, 2008, 2009] 55 | // With sortMergedLabels set to false, tick labels will be: 56 | // > [2006, 2008, 2009, 2007] 57 | // 58 | // Note, this property is specified on the renderOptions for the 59 | // axes when creating a plot: 60 | // > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}} 61 | this.sortMergedLabels = false; 62 | }; 63 | 64 | $.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); 65 | $.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer; 66 | 67 | $.jqplot.CategoryAxisRenderer.prototype.init = function(options){ 68 | this.groups = 1; 69 | this.groupLabels = []; 70 | this._groupLabels = []; 71 | this._grouped = false; 72 | this._barsPerGroup = null; 73 | this.reverse = false; 74 | // prop: tickRenderer 75 | // A class of a rendering engine for creating the ticks labels displayed on the plot, 76 | // See <$.jqplot.AxisTickRenderer>. 77 | // this.tickRenderer = $.jqplot.AxisTickRenderer; 78 | // this.labelRenderer = $.jqplot.AxisLabelRenderer; 79 | $.extend(true, this, {tickOptions:{formatString:'%d'}}, options); 80 | var db = this._dataBounds; 81 | // Go through all the series attached to this axis and find 82 | // the min/max bounds for this axis. 83 | for (var i=0; i db.max || db.max == null) { 96 | db.max = d[j][0]; 97 | } 98 | } 99 | else { 100 | if (d[j][1] < db.min || db.min == null) { 101 | db.min = d[j][1]; 102 | } 103 | if (d[j][1] > db.max || db.max == null) { 104 | db.max = d[j][1]; 105 | } 106 | } 107 | } 108 | } 109 | 110 | if (this.groupLabels.length) { 111 | this.groups = this.groupLabels.length; 112 | } 113 | }; 114 | 115 | 116 | $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() { 117 | // we're are operating on an axis here 118 | var ticks = this._ticks; 119 | var userTicks = this.ticks; 120 | var name = this.name; 121 | // databounds were set on axis initialization. 122 | var db = this._dataBounds; 123 | var dim, interval; 124 | var min, max; 125 | var pos1, pos2; 126 | var tt, i; 127 | 128 | // if we already have ticks, use them. 129 | if (userTicks.length) { 130 | // adjust with blanks if we have groups 131 | if (this.groups > 1 && !this._grouped) { 132 | var l = userTicks.length; 133 | var skip = parseInt(l/this.groups, 10); 134 | var count = 0; 135 | for (var i=skip; i 1 && !this._grouped) { 248 | var l = labels.length; 249 | var skip = parseInt(l/this.groups, 10); 250 | var count = 0; 251 | for (var i=skip; i0 && track'); 325 | 326 | if (this.name == 'xaxis' || this.name == 'x2axis') { 327 | this._elem.width(this._plotDimensions.width); 328 | } 329 | else { 330 | this._elem.height(this._plotDimensions.height); 331 | } 332 | 333 | // create a _label object. 334 | this.labelOptions.axis = this.name; 335 | this._label = new this.labelRenderer(this.labelOptions); 336 | if (this._label.show) { 337 | var elem = this._label.draw(ctx, plot); 338 | elem.appendTo(this._elem); 339 | } 340 | 341 | var t = this._ticks; 342 | for (var i=0; i'); 355 | elem.html(this.groupLabels[i]); 356 | this._groupLabels.push(elem); 357 | elem.appendTo(this._elem); 358 | } 359 | } 360 | return this._elem; 361 | }; 362 | 363 | // called with scope of axis 364 | $.jqplot.CategoryAxisRenderer.prototype.set = function() { 365 | var dim = 0; 366 | var temp; 367 | var w = 0; 368 | var h = 0; 369 | var lshow = (this._label == null) ? false : this._label.show; 370 | if (this.show) { 371 | var t = this._ticks; 372 | for (var i=0; i dim) { 382 | dim = temp; 383 | } 384 | } 385 | } 386 | 387 | var dim2 = 0; 388 | for (var i=0; i dim2) { 397 | dim2 = temp; 398 | } 399 | } 400 | 401 | if (lshow) { 402 | w = this._label._elem.outerWidth(true); 403 | h = this._label._elem.outerHeight(true); 404 | } 405 | if (this.name == 'xaxis') { 406 | dim += dim2 + h; 407 | this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); 408 | } 409 | else if (this.name == 'x2axis') { 410 | dim += dim2 + h; 411 | this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); 412 | } 413 | else if (this.name == 'yaxis') { 414 | dim += dim2 + w; 415 | this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); 416 | if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { 417 | this._label._elem.css('width', w+'px'); 418 | } 419 | } 420 | else { 421 | dim += dim2 + w; 422 | this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); 423 | if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { 424 | this._label._elem.css('width', w+'px'); 425 | } 426 | } 427 | } 428 | }; 429 | 430 | // called with scope of axis 431 | $.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) { 432 | var ticks = this._ticks; 433 | var max = this.max; 434 | var min = this.min; 435 | var offmax = offsets.max; 436 | var offmin = offsets.min; 437 | var lshow = (this._label == null) ? false : this._label.show; 438 | var i; 439 | 440 | for (var p in pos) { 441 | this._elem.css(p, pos[p]); 442 | } 443 | 444 | this._offsets = offsets; 445 | // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. 446 | var pixellength = offmax - offmin; 447 | var unitlength = max - min; 448 | 449 | if (!this.reverse) { 450 | // point to unit and unit to point conversions references to Plot DOM element top left corner. 451 | 452 | this.u2p = function(u){ 453 | return (u - min) * pixellength / unitlength + offmin; 454 | }; 455 | 456 | this.p2u = function(p){ 457 | return (p - offmin) * unitlength / pixellength + min; 458 | }; 459 | 460 | if (this.name == 'xaxis' || this.name == 'x2axis'){ 461 | this.series_u2p = function(u){ 462 | return (u - min) * pixellength / unitlength; 463 | }; 464 | this.series_p2u = function(p){ 465 | return p * unitlength / pixellength + min; 466 | }; 467 | } 468 | 469 | else { 470 | this.series_u2p = function(u){ 471 | return (u - max) * pixellength / unitlength; 472 | }; 473 | this.series_p2u = function(p){ 474 | return p * unitlength / pixellength + max; 475 | }; 476 | } 477 | } 478 | 479 | else { 480 | // point to unit and unit to point conversions references to Plot DOM element top left corner. 481 | 482 | this.u2p = function(u){ 483 | return offmin + (max - u) * pixellength / unitlength; 484 | }; 485 | 486 | this.p2u = function(p){ 487 | return min + (p - offmin) * unitlength / pixellength; 488 | }; 489 | 490 | if (this.name == 'xaxis' || this.name == 'x2axis'){ 491 | this.series_u2p = function(u){ 492 | return (max - u) * pixellength / unitlength; 493 | }; 494 | this.series_p2u = function(p){ 495 | return p * unitlength / pixellength + max; 496 | }; 497 | } 498 | 499 | else { 500 | this.series_u2p = function(u){ 501 | return (min - u) * pixellength / unitlength; 502 | }; 503 | this.series_p2u = function(p){ 504 | return p * unitlength / pixellength + min; 505 | }; 506 | } 507 | 508 | } 509 | 510 | 511 | if (this.show) { 512 | if (this.name == 'xaxis' || this.name == 'x2axis') { 513 | for (i=0; i= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one. 577 | if (this._ticks[j]._elem && this._ticks[j].label != " ") { 578 | var t = this._ticks[j]._elem; 579 | var p = t.position(); 580 | mid += p.left + t.outerWidth(true)/2; 581 | count++; 582 | } 583 | } 584 | mid = mid/count; 585 | this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)}); 586 | this._groupLabels[i].css(labeledge[0], labeledge[1]); 587 | } 588 | } 589 | else { 590 | for (i=0; i 0) { 610 | shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; 611 | } 612 | else { 613 | shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; 614 | } 615 | break; 616 | case 'middle': 617 | // if (t.angle > 0) { 618 | // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; 619 | // } 620 | // else { 621 | // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; 622 | // } 623 | shim = -t.getHeight()/2; 624 | break; 625 | default: 626 | shim = -t.getHeight()/2; 627 | break; 628 | } 629 | } 630 | else { 631 | shim = -t.getHeight()/2; 632 | } 633 | 634 | var val = this.u2p(t.value) + shim + 'px'; 635 | t._elem.css('top', val); 636 | t.pack(); 637 | } 638 | } 639 | 640 | var labeledge=['left', 0]; 641 | if (lshow) { 642 | var h = this._label._elem.outerHeight(true); 643 | this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); 644 | if (this.name == 'yaxis') { 645 | this._label._elem.css('left', '0px'); 646 | labeledge = ['left', this._label._elem.outerWidth(true)]; 647 | } 648 | else { 649 | this._label._elem.css('right', '0px'); 650 | labeledge = ['right', this._label._elem.outerWidth(true)]; 651 | } 652 | this._label.pack(); 653 | } 654 | 655 | // draw the group labels, position top here, do left after label position. 656 | var step = parseInt(this._ticks.length/this.groups, 10) + 1; // step is one more than before as we don't want to have overlaps in loops 657 | for (i=0; i= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one. 662 | if (this._ticks[j]._elem && this._ticks[j].label != " ") { 663 | var t = this._ticks[j]._elem; 664 | var p = t.position(); 665 | mid += p.top + t.outerHeight()/2; 666 | count++; 667 | } 668 | } 669 | mid = mid/count; 670 | this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2}); 671 | this._groupLabels[i].css(labeledge[0], labeledge[1]); 672 | 673 | } 674 | } 675 | } 676 | }; 677 | 678 | 679 | })(jQuery); 680 | -------------------------------------------------------------------------------- /app/static/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.5",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.5",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.5",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.5",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.5",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.5",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.5",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); --------------------------------------------------------------------------------