Commit ef5109ea authored by Romain Loth's avatar Romain Loth

Merge remote-tracking branch 'romain_static/master'

parents aeb252da b39641de
# For now
As of nov 2016, the flask framework isn't used as a static form with cgibin posttreatment is enough for our needs.
This folder contains nov 2016 registration form and cgi
=======================================================
The flask framework will probably be re-used to generate more diverse forms in the future.
=> the form is static and uses js for validation etc
=> the registration credentials are transmitted to a doors prototype
=> the answers are POSTed to a cgi script that writes the new users in a local DB
# Flask-User starter app
This code base serves as a great starting point to write your next Flask application
Official repo:
git clone https://github.com/lingthio/Flask-User-starter-app regcomex
export LC_ALL=C
sudo apt-get install postgresql-server-dev-9.4
export ENV_SETTINGS_FILE=.../regcomex/env_settings.py
virtualenv -p /usr/bin/python3 env
source env/bin/activate
pip install -r requirements.txt
pip list --outdated | sed 's/(.*//g' | xargs -n1 pip install -U
app/templates/layout.html :29: change to {% if current_user.is_authenticated %}
app/templates/core/home_page.html : 8: change to {% if not current_user.is_authenticated %}
python manage.py init_db
./runserver.sh
NGINX conf:
location /a {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Script-Name /a;
}
## Acknowledgements
With thanks to the following Flask extensions:
* [Alembic](alembic.readthedocs.org)
* [Flask-Migrate](flask-migrate.readthedocs.org)
* [Flask-User](pythonhosted.org/Flask-User/)
[Flask-User-starter-app](https://github.com/lingthio/Flask-User-starter-app) was used as a starting point for this code repository.
# Please consider leaving the line above in your project's README file. Thank you.
contact: `romain.loth@iscpif.fr`
"""
Flask server used to test the registration page for comex app
(in production this script is not used anymore
=> the registration page will be a static form
with js and cgi-bin answers management )
=> TODO more generic use the server to generate the form and validation
"""
__author__ = "CNRS"
__copyright__ = "Copyright 2016 ISCPIF-CNRS"
__version__ = "1"
__email__ = "romain.loth@iscpif.fr"
__status__ = "Test"
from flask import Flask, render_template, request
from ctypes import c_int
from time import sleep
# ============= app creation =============
app = Flask(__name__)
app.config['DEBUG'] = True
# ============= views =============
@app.route("/", methods=['GET','POST'])
def one_big_form():
if request.method == 'GET':
return render_template("base_layout.html")
elif request.method == 'POST':
# ex: request.form = ImmutableMultiDict([('initials', 'R.L.'), ('email', 'romain.loth@iscpif.fr'), ('last_name', 'Loth'), ('country', 'France'), ('first_name', 'Romain'), ('my-captchaHash', '-773776109'), ('my-captcha', 'TSZVIN')])
# print("GOT ANSWERS <<========<<", request.form)
# 1 - testing the captcha answer
userinput = request.form['my-captcha']
userhash = re_hash(userinput)
captchash = int(request.form['my-captchaHash'])
if userhash != captchash:
print("captcha rejected")
sleep(3)
return render_template("thank_you.html", form_accepted = False)
# normal case
else:
print("OK accepted")
return render_template("thank_you.html", form_accepted = True)
# def re_hash(userinput, salt="#salt"):
def re_hash(userinput, salt=""):
"""
my rewrite of keith-wood.name/realPerson.html python's version
"""
hashk = 5381
value = userinput.upper() + salt
for i, char in enumerate(value):
hashk = c_int( ((hashk << 5) + hashk + ord(char)) & 0xFFFFFFFF ).value
# bitwise masks 0xFFFFFFFF to go back to int32 each time
# c_int( previous ).value to go from unsigned ints to c signed ints each time
print(i, hashk)
return hashk
if __name__ == "__main__":
app.run()
Flask templates
===============
More interpolated templates (only useful on dev server by flask)
This diff is collapsed.
<!DOCTYPE html>
<html lang="fr-FR">
<head>
<meta charset="utf-8">
<title>Formulaire Community Explorer : se ré-enregistrer</title>
<meta name="description" content="Formulaire d'enregistrement sur la plateforme Community Explorer (ISCPIF CNRS UPS 3611)">
<meta name="keywords" content="complex systems, community, registration form">
<!-- CSS -->
<link type=text/css rel=stylesheet href="{{ url_for('static', filename='css/bootstrap.min.css') }}">
<link type=text/css rel=stylesheet href="{{ url_for('static', filename='css/topbar_bootstrap_retrocompatibility.css') }}">
<link type=text/css rel=stylesheet href="{{ url_for('static', filename='js/jquery-ui-1.12.1/jquery-ui.min.css') }}">
<style type="text/css" media="screen">
.white { color:#fff ; }
.page {
margin-top: 45px; /* topbar height is 40px */
}
/* for intro text */
.mini-hero {
margin-top: 1.5em;
font-size: 18px;
line-height: 27px;
}
/* page sections: style snippets from old bootstrap h2 */
h2.oldstyle {
font-family: Ubuntu, sans-serif;
font-size: 24px;
font-weight: bold;
line-height: 18px ;
}
.spacerrow {
height: 5em;
}
.bigspacerrow {
height: 50em;
}
</style>
<!-- ## JS ## -->
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//piwik.iscpif.fr/";
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', '4']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="//piwik.iscpif.fr/piwik.php?idsite=4" style="border:0;" alt="" /></p></noscript>
<!-- End Piwik Code -->
</head>
<body>
<div class="topbar" style="opacity: 0.93;">
<div class="topbar-inner">
<div class="container-fluid">
<a class="brand" href="http://communityexplorer.org/index.html">
<span class="glyphicon glyphicon-home white"></i></a>
<ul class="white nav">
<li>
<a id="truc" href="http://communityexplorer.org/#"> <strong>Complex systems community explorer</strong></a>
</li>
</ul>
</div>
</div>
</div>
<div class="page container-fluid">
<div class="row spacerrow">&nbsp;</div>
<div class="row">
<div class="spacer col-sm-1 col-md-1">&nbsp;</div>
<div class="my_form_box col-sm-8 col-md-8">
<!-- INTRODUCTION TEXT -->
<div id="intro">
<h2 class="oldstyle">Registration form</h2>
<p class="mini-hero">
{% if form_accepted %}
Thank you for your answers ! We'll soon update the <strong>Community Explorer</strong> database with all the new information.
{% else %}
Your answers couldn't be accepted because you filled some wrong information in the verification test !
{% endif %}
</p>
</div>
</div>
<div class="spacer col-sm-2 col-md-2">&nbsp;</div>
</div>
<div class="row bigspacerrow">&nbsp;</div>
<!-- FOOTER TEXT AND LINKS -->
<footer>
<!-- This directory is maintained by the <a href="http://cssociety.org" target="blank">Complex Systems Society</a>
and the <a href="http://iscpif.fr" target="blank">Complex Systems Institute of Paris Ile-de-France</a>.<br/>-->
<center>
<a href="http://communityexplorer.org/about.html"><span class="glyphicon glyphicon-question-sign"></span> About</a> -
<a href="http://moma.csregistry.org/feedback" target="BLANK"><span class="glyphicon glyphicon-repeat"></span> Feedback</a> -
<a href="http://communityexplorer.org/privacy.html"> <span class="glyphicon glyphicon-list-alt"></span> Privacy</a>
<br>
Directory maintained by the
<a href="http://cssociety.org/" target="blank"> Complex Systems Society</a> and the
<a href="http://iscpif.fr/" target="blank">Complex Systems Institute of Paris Ile-de-France</a>.
<br>
<a href="http://cssociety.org/" target="_BLANK">
<img src="{{ url_for('static', filename='images/css.png') }}" alt="http://cssociety.org"
style="border: none; margin-bottom : -6px;"
title="isc-pif" height="25px">
</a>
<a href="http://iscpif.fr/">
<img src="{{ url_for('static', filename='images/iscpif_short.png') }}" alt="iscpif.fr"
style="border: none; margin-bottom : -6px;"
title="isc-pif">
</a>
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" target="blank">
<img alt="Creative Commons License" style="border: none; margin-bottom : -6px;" src="{{ url_for('static', filename='images/cc.png') }}" height="20px">
</a> -
<!-- <a href="http://moma.csregistry.org/" target="_BLANK"> MOMA</a> - -->
<a href="http://iscpif.fr/" target="_BLANK">ISC-PIF</a> -
<a href="http://www.cnrs.fr/fr/recherche/index.htm" target="_BLANK">CNRS</a>.
</center>
<p>&nbsp;</p>
</footer>
</div>
</body>
</html>
This diff is collapsed.
#!/usr/bin/env python3
"""
Package: Registration page for comex app
File: CGI script for collecting form
Context:
- static input form validated fields and checked if all were present
(base_form.html + static/js/comex_reg_form_controllers.js)
- Doors recorded the email + password combination
- POSSIBLE Doors validated the email was new ??
"""
__author__ = "CNRS"
__copyright__ = "Copyright 2016 ISCPIF-CNRS"
__version__ = "1"
__email__ = "romain.loth@iscpif.fr"
__status__ = "Test"
from cgi import FieldStorage
from traceback import format_exc, format_tb
from ctypes import c_int32
from re import sub
from jinja2 import Template, Environment, FileSystemLoader
from sys import stdout # for direct buffer write of utf-8 bytes
from sqlite3 import connect
# debug # comment before prod -------------------------8<--------------------
# import cgitb
# cgitb.enable()
# from glob import glob
# --------------------------------------------------------8<--------------------
# templating setup
templating_env = Environment(loader = FileSystemLoader('../templates'),
autoescape = False)
########### PARAMS ###########
# all columns as they are declared in form & DB as tuple:
# NAME, NOT NULL, N or MAXCHARS (if applicable)
COLS = [ ("doors_uid", True, 36),
("last_modified_date", True, 24), # ex 2016-11-16T17:47:07.308Z
("email", True, 255),
("initials", True, 7),
("country", True, 60),
("first_name", True, 30),
("middle_name", False, 30),
("last_name", True, 50),
("jobtitle", True, 30),
("keywords", True, 350),
("institution", True, 120),
("institution_type", True, 50),
("team_lab", False, 50),
("institution_city", False, 50),
("interests_text", False, 1200),
("community_hashtags", False, 350),
("gender", False, 1), # M|F
("pic_file", False, None)]
########### SUBS ###########
def re_hash(userinput, salt="verylonverylongverylonverylongverylonverylong"):
"""
Build the captcha's verification hash server side
(my rewrite of keith-wood.name/realPerson.html python's version)
NB the number of iterations is prop to salt length
<< 5 pads binary repr by 5 zeros on the right (including possible change of sign)
NB in all languages except python it truncates on the left
=> here we need to emulate the same mechanism
=> using c_int32() works well
"""
hashk = 5381
value = userinput.upper() + salt
# debug
# print_to_buffer("<br/><br/><br/><br/><br/><br/>evaluated value:"+value)
for i, char in enumerate(value):
hashk = c_int32(hashk << 5).value + hashk + ord(char)
# debug iterations
# print_to_buffer(str(i) + ": " + str(hashk) + '<br/>')
return hashk
def get_template(filename):
"""
Retrieve a jinja2 template from ../templates
"""
return templating_env.get_template(filename)
def print_to_buffer(stringy):
"""
print() with utf-8 in a cgi doesn't work well because print is
connected to sys.stdout which has hardcoded encoding ASCII...
(but in reality html can of course have utf-8 bytes in cgi)
so to avoid print function we write to sys.stdout.buffer
(inspired by http://stackoverflow.com/questions/14860034)
"""
stdout.buffer.write((stringy+'\n').encode('utf-8'))
def sanitize(value):
"""
simple and radical: leaves only alphanum and '.' '-' ':' ',' '(', ')', ' '
TODO better
"""
vtype = type(value)
str_val = str(value)
clean_val = sub(r'^\s+', '', str_val)
clean_val = sub(r'\s+$', '', clean_val)
san_val = sub(r'[^\w@\.-:,() ]', '_', clean_val)
if vtype not in [int, str]:
raise ValueError("Value has an incorrect type %s" % str(vtype))
else:
# cast back to orginal type
san_typed_val = vtype(san_val)
return san_typed_val
def save_to_db(safe_recs_arr):
"""
see COLS and table_specifications.md
"""
# expected number of vals (for instance 3 vals ===> "(?,?,?)" )
db_mask = '('+ ','.join(['?' for i in range(len(COLS))]) + ')'
# £TODO check if email exists first
# yes =>propose login via doors + overwrite ?)
# no => proceed
reg_db = connect('../data/registered.db')
reg_db_c = reg_db.cursor()
reg_db_c.execute('INSERT INTO comex_registrations VALUES' + db_mask , safe_recs_arr)
reg_db.commit()
reg_db.close()
########### MAIN ###########
if __name__ == "__main__":
# any response must have headers (not managed by the templating)
# ==============================
print_to_buffer("Content-type: text/html")
print_to_buffer('') # blank line <=> end of headers
# reception: the cgi library gets vars from html form within received http POST
# ==========
incoming_data = FieldStorage()
# init vars
clean_records = {}
missing_fields = []
template_thanks = get_template("thank_you.html")
captcha_accepted = False
# for captcha validation -----------------------------------------------
if 'my-captcha' in incoming_data:
captcha_userinput = incoming_data['my-captcha'].value
captcha_verifhash = int(incoming_data['my-captchaHash'].value)
# dbg
# print_to_buffer(str(captcha_verifhash))
captcha_userhash = re_hash(captcha_userinput)
captcha_accepted = (captcha_userhash == captcha_verifhash)
# ----------------------------------------------------------------------
# debug data keys
# print_to_buffer("<br/><br/><br/><br/><br/><br/><br/>")
# print_to_buffer(str([k for k in incoming_data]))
# print_to_buffer(str(incoming_data))
if captcha_accepted:
# read in + sanitize values
# =========================
# NB password values have already been sent by ajax to Doors
# we should have all the mandatory fields (checked in client-side js)
for field_info in COLS:
field = field_info[0]
if field in incoming_data:
if field not in ["doors_uid", "last_modified_date", "pic_file"]:
clean_records[field] = sanitize(incoming_data[field].value)
# these 3 fields were already validated actually :)
else:
clean_records[field] = incoming_data[field].value
# debug cleaned data keys
# print_to_buffer("<br/><br/><br/><br/><br/><br/><br/>")
# print_to_buffer(str(clean_records))
# save to DB
# ===========
save_to_db([clean_records.get(k[0], None) for k in COLS])
# show received values in template
# ================================
print_to_buffer(
template_thanks.render(
form_accepted = captcha_accepted,
# for debug
records = clean_records,
message = ""
)
)
# except Exception as errr:
# print_to_buffer("<h3>There was an error:</h3")
# print_to_buffer("<p style='font-family:monospace; font-size:80%'")
# print_to_buffer(sub(r'\n', "<br/>", format_exc()))
# print_to_buffer("</p>")
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "Hello, World."
#!/usr/bin/env python3
"""
Package: Registration page for comex app
simple script to test the cgi user (apache?)
=> to know what db permissions to set
(inspired by stackoverflow.com/a/25574419)
"""
__author__ = "CNRS"
__copyright__ = "Copyright 2016 ISCPIF-CNRS"
__version__ = "1"
__email__ = "romain.loth@iscpif.fr"
__status__ = "Test"
from os import getegid
from getpass import getuser
from sys import stdout
# debug
import cgitb
cgitb.enable()
def print_to_buffer(stringy):
"""
print() with utf-8 in a cgi doesn't work well because print is
connected to sys.stdout which has hardcoded encoding ASCII...
(but in reality html can of course have utf-8 bytes in cgi)
so to avoid print function we write to sys.stdout.buffer
(inspired by http://stackoverflow.com/questions/14860034)
"""
stdout.buffer.write((stringy).encode('utf-8')+b'\n')
########### MAIN ###########
if __name__ == "__main__":
# any response must have this
print_to_buffer("Content-type: text/html")
print_to_buffer('') # blank line <=> end of headers
print_to_buffer( "Env user id: %s <br/>" % getegid() )
print_to_buffer( "Real user: %s <br/>" % getuser() )
Memo for chown
--------------
To ensure correct access rights to the DB,
the entire folder data/ should should be owned
by www-data or a user member of www-data group.
Exemple:
```
sudo chown -R romain:www-data data/
```
doors_uid char(36) not null unique,
last_modified_date char(10) not null,
email varchar(255) not null unique primary key,
initials varchar(7) not null,
country varchar(60) not null,
first_name varchar(30) not null,
middle_name varchar(30),
last_name varchar(50) not null,
jobtitle varchar(30) not null,
keywords varchar(350) not null,
institution varchar(120) not null,
institution_type varchar(50) not null,
team_lab varchar(50),
institution_city varchar(50),
interests_text varchar(1200),
community_hashtags varchar(350),
gender char(1),
pic_file blob
#### Why and what?
After comex-reg setup, one may want to run a doors server to interact with.
1) To do that we need to install doors
2) Doors is served by a jetty server so we need to do a few things
## Doors installation
First you'll need to install sbt (for scala builds): see http://www.scala-sbt.org/
```bash
# any installation dir is ok...
cd /~
git clone https://github.com/ISCPIF/doors.git
cd doors/application
sbt
```
Then we build and run the scala app in sbt command line
```sbt
project lab
run
```
## Server conf
### If nginx
see more info in the [nginx doc for a jetty](https://www.nginx.com/resources/wiki/start/topics/examples/javaservers)
#### gist
```
proxy_pass http://localhost:8080; # <== jetty app referenced by nginx
```
### If apache
see more info in the [jetty doc for apache](http://wiki.eclipse.org/Jetty/Tutorial/Apache#Configuring_Apache)
#### Required apache mod
```
sudo a2enmod proxy_ajp # <= needed for proxy relay
```
#### Expected apache conf
```
TODO
## Doors status protocol
**TODO**
DOORS callDoors
// need to handle the various return formats
// then send one of 2 * 2 possibilities (+ unknown exceptions)
// action | response
// login login ok
// login can't login
// register register ok
// register can't register
// register login exists // ML remark : this is redundant
// TODO verif protocole de statuts
```
{
"status": "login ok",
"userInfo": {
"id": {
"id": "78407900-6f48-44b8-ab37-503901f85458"
},
"password": "68d23eab21abab38542184e8fca2199d",
"name": "TODO",
"hashAlgorithm": "PBKDF2",
"hashParameters": "{\n \"iterations\" : 1000,\n \"keyLenght\" : 128\n}"
}
}
To remember the setup
#### Dir permissions
```
# in regcomex dir
chown -R rloth:www-data .
# cgi executables
chmod 754 cgi-bin/* # <=> u+rwx, g+rx, o+r
# writeable data
chmod 774 data
chmod 774 data/registered.db # <=> u+rwx, g+rwx, o+r
```
#### Required apache mod
```
sudo a2enmod cgi # <= needed for cgi
```
#### Expected apache conf
```
Alias /comex-reg "/home/rloth/comex/regcomex"
# for main directory
<Directory "/home/rloth/comex/regcomex">
# no dir listing, but allow symlinks
Options -Indexes +FollowSymLinks
# no htaccess
AllowOverride None
# directive's conflict resolution (last one prevails)
Order allow,deny
# which IPs can access
Allow from all # old but necessary on tina 2016-11
Require all granted # new but insufficient --- // ---
</Directory>
# for cgi directory
ScriptAlias /cgi-bin/ "/home/rloth/comex/regcomex/cgi-bin/"
<Directory "/home/rloth/comex/regcomex/cgi-bin">
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
AddHandler cgi-script .cgi .pl .py
AllowOverride None
Require all granted
</Directory>
```
## Parameters for *`data/registered.db`*
registered.db is a sqlite3 db, with 2 tables:
```
-- test_table: used in debug
-- #########################
create table test_table (
email varchar(255) unique,
initials varchar(7)
) ;
-- real_table: used in prod
-- ########################
create table comex_registrations (
doors_uid char(36) not null unique,
-- ISO stamp like 2016-11-16T17:47:07.308Z
last_modified_date char(24) not null,
email varchar(255) not null unique primary key,
initials varchar(7) not null,
country varchar(60) not null,
first_name varchar(30) not null,
middle_name varchar(30),
last_name varchar(50) not null,
jobtitle varchar(30) not null,
keywords varchar(350) not null,
institution varchar(120) not null,
institution_type varchar(50) not null,
team_lab varchar(50),
institution_city varchar(50),
interests_text varchar(1200),
community_hashtags varchar(350),
gender char(1),
pic_file blob
) ;
```
base_form.html
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
.white { color:#fff ; }
.red { color:#910 ; }
.green { color:#161 ; }
.grey { color:#554 ; }
/* not used at present but could be useful for autompleted inputs */
.autocomp {
}
.page {
margin-top: 45px; /* topbar height is 40px */
}
/* for intro text */
.mini-hero {
margin-top: 1.5em;
font-size: 18px;
line-height: 27px;
}
/* a "subpage" container */
.subpage {
width: 100%;
max-width: 55em;
display: none ; /*switching page <=> displaying it */
}
/* ==> a question + input block <== */
.question {
padding: 0 1em;
margin-bottom: 2em;
}
.conditional-q {
display: none;
}
#cnil_warning {
/*text-align: center;*/
}
.operation {
color: #554 ;
}
#mainpagelink:hover {
background-color: transparent !important;
}
/* small label inside addon group*/
.smlabel {
min-width: 7.5em;
}
/* the main validation message (a special legend) */
#main_validation_message {
font-size: 200%;
text-align:center;
/*color: #554 ;*/
}
/* the doors status message (a special legend) */
#doors_ret_message {
font-size: 150%;
text-align:center;
color: #554 ;
display:none;
/*padding: .5em 0 .5em .5em ;*/
padding: 0;
}
/* the question's additional legend or caption */
.legend {
font-family: Cambria, serif;
color: #554 ;
font-style: italic;
text-align:right;
padding: .5em 0 .5em .5em ;
margin: 0;
}
/* the picture preview */
#box_show_pic {
background-color: #554;
border: none ;
width:250px;
height:250px;
margin-bottom: 2em;
display: none;
}
#show_pic {
/* styled via js in static/js/comex_reg_form_controllers.js */
}
/* page sections: style snippets from old bootstrap h2 */
h2.oldstyle {
font-family: Ubuntu, sans-serif;
font-size: 24px;
font-weight: bold;
line-height: 18px ;
}
/* big categories: like form sections etc. */
h3.formcat {
margin-top: 2em;
}
.spacerrow {
height: 4em;
}
.bigspacerrow {
height: 50em;
}
.realperson-challenge {
float:right;
}
.realperson-text {
padding: 0 2em;
}
.realperson-regen {
color: #554 ;
}
.bigspacerrow {
height: 50em;
}
.raw-responses {
font-family: Calibri, sans-serif ;
font-size: 80%;
line-height: 90% ;
background-color: #554;
color: white;
padding-bottom: 3em
}
/*!
* Excerpt from Bootstrap v1.4.0 Copyright 2011 Twitter, Inc
* with all top toolbar elements' css as they were back then...
*/
.topbar {
height: 40px;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 10000;
overflow: visible;
}
.topbar a {
color: #bfbfbf;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.topbar h3 a:hover, .topbar .brand:hover, .topbar ul .active > a {
background-color: #333;
background-color: rgba(255, 255, 255, 0.05);
color: #fff;
text-decoration: none;
}
.topbar h3 {
position: relative;
}
.topbar h3 a, .topbar .brand {
float: left;
display: block;
padding: 8px 20px 12px;
margin-left: -20px;
color: #fff;
font-size: 20px;
font-weight: 200;
line-height: 1;
}
.topbar p {
margin: 0;
line-height: 40px;
}
.topbar p a:hover {
background-color: transparent;
color: #fff;
}
.topbar form {
float: left;
margin: 5px 0 0 0;
position: relative;
filter: alpha(opacity=100);
-khtml-opacity: 1;
-moz-opacity: 1;
opacity: 1;
}
.topbar form.pull-right {
float: right;
}
.topbar input {
background-color: #444;
background-color: rgba(255, 255, 255, 0.3);
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: normal;
font-weight: 13px;
line-height: 1;
padding: 4px 9px;
color: #fff;
color: rgba(255, 255, 255, 0.75);
border: 1px solid #111;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.25);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.25);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.25);
-webkit-transition: none;
-moz-transition: none;
-ms-transition: none;
-o-transition: none;
transition: none;
}
.topbar input:-moz-placeholder {
color: #e6e6e6;
}
.topbar input::-webkit-input-placeholder {
color: #e6e6e6;
}
.topbar input:hover {
background-color: #bfbfbf;
background-color: rgba(255, 255, 255, 0.5);
color: #fff;
}
.topbar input:focus, .topbar input.focused {
outline: 0;
background-color: #fff;
color: #404040;
text-shadow: 0 1px 0 #fff;
border: 0;
padding: 5px 10px;
-webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
-moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
}
.topbar-inner, .topbar .fill {
background-color: #222;
background-color: #222222;
background-repeat: repeat-x;
background-image: -khtml-gradient(linear, left top, left bottom, from(#333333), to(#222222));
background-image: -moz-linear-gradient(top, #333333, #222222);
background-image: -ms-linear-gradient(top, #333333, #222222);
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #333333), color-stop(100%, #222222));
background-image: -webkit-linear-gradient(top, #333333, #222222);
background-image: -o-linear-gradient(top, #333333, #222222);
background-image: linear-gradient(top, #333333, #222222);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
}
.topbar div > ul, .nav {
display: block;
float: left;
margin: 0 10px 0 0;
position: relative;
left: 0;
}
.topbar div > ul > li, .nav > li {
display: block;
float: left;
}
.topbar div > ul a, .nav a {
display: block;
float: none;
padding: 10px 10px 11px;
line-height: 19px;
text-decoration: none;
}
.topbar div > ul a:hover, .nav a:hover {
color: #fff;
text-decoration: none;
}
.topbar div > ul .active > a, .nav .active > a {
background-color: #222;
background-color: rgba(0, 0, 0, 0.5);
}
.topbar div > ul.secondary-nav, .nav.secondary-nav {
float: right;
margin-left: 10px;
margin-right: 0;
}
.topbar div > ul.secondary-nav .menu-dropdown,
.nav.secondary-nav .menu-dropdown,
.topbar div > ul.secondary-nav .dropdown-menu,
.nav.secondary-nav .dropdown-menu {
right: 0;
border: 0;
}
.topbar div > ul a.menu:hover,
.nav a.menu:hover,
.topbar div > ul li.open .menu,
.nav li.open .menu,
.topbar div > ul .dropdown-toggle:hover,
.nav .dropdown-toggle:hover,
.topbar div > ul .dropdown.open .dropdown-toggle,
.nav .dropdown.open .dropdown-toggle {
background: #444;
background: rgba(255, 255, 255, 0.05);
}
.topbar div > ul .menu-dropdown,
.nav .menu-dropdown,
.topbar div > ul .dropdown-menu,
.nav .dropdown-menu {
background-color: #333;
}
.topbar div > ul .menu-dropdown a.menu,
.nav .menu-dropdown a.menu,
.topbar div > ul .dropdown-menu a.menu,
.nav .dropdown-menu a.menu,
.topbar div > ul .menu-dropdown .dropdown-toggle,
.nav .menu-dropdown .dropdown-toggle,
.topbar div > ul .dropdown-menu .dropdown-toggle,
.nav .dropdown-menu .dropdown-toggle {
color: #fff;
}
.topbar div > ul .menu-dropdown a.menu.open,
.nav .menu-dropdown a.menu.open,
.topbar div > ul .dropdown-menu a.menu.open,
.nav .dropdown-menu a.menu.open,
.topbar div > ul .menu-dropdown .dropdown-toggle.open,
.nav .menu-dropdown .dropdown-toggle.open,
.topbar div > ul .dropdown-menu .dropdown-toggle.open,
.nav .dropdown-menu .dropdown-toggle.open {
background: #444;
background: rgba(255, 255, 255, 0.05);
}
.topbar div > ul .menu-dropdown li a,
.nav .menu-dropdown li a,
.topbar div > ul .dropdown-menu li a,
.nav .dropdown-menu li a {
color: #999;
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
}
.topbar div > ul .menu-dropdown li a:hover,
.nav .menu-dropdown li a:hover,
.topbar div > ul .dropdown-menu li a:hover,
.nav .dropdown-menu li a:hover {
background-color: #191919;
background-repeat: repeat-x;
background-image: -khtml-gradient(linear, left top, left bottom, from(#292929), to(#191919));
background-image: -moz-linear-gradient(top, #292929, #191919);
background-image: -ms-linear-gradient(top, #292929, #191919);
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #292929), color-stop(100%, #191919));
background-image: -webkit-linear-gradient(top, #292929, #191919);
background-image: -o-linear-gradient(top, #292929, #191919);
background-image: linear-gradient(top, #292929, #191919);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#292929', endColorstr='#191919', GradientType=0);
color: #fff;
}
.topbar div > ul .menu-dropdown .active a,
.nav .menu-dropdown .active a,
.topbar div > ul .dropdown-menu .active a,
.nav .dropdown-menu .active a {
color: #fff;
}
.topbar div > ul .menu-dropdown .divider,
.nav .menu-dropdown .divider,
.topbar div > ul .dropdown-menu .divider,
.nav .dropdown-menu .divider {
background-color: #222;
border-color: #444;
}
.topbar ul .menu-dropdown li a, .topbar ul .dropdown-menu li a {
padding: 4px 15px;
}
.topbar .dropdown-menu a, .dropdown-menu a {
display: block;
padding: 4px 15px;
clear: both;
font-weight: normal;
line-height: 18px;
color: #808080;
text-shadow: 0 1px 0 #fff;
}
.topbar .dropdown-menu a:hover,
.dropdown-menu a:hover,
.topbar .dropdown-menu a.hover,
.dropdown-menu a.hover {
background-color: #dddddd;
background-repeat: repeat-x;
background-image: -khtml-gradient(linear, left top, left bottom, from(#eeeeee), to(#dddddd));
background-image: -moz-linear-gradient(top, #eeeeee, #dddddd);
background-image: -ms-linear-gradient(top, #eeeeee, #dddddd);
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #eeeeee), color-stop(100%, #dddddd));
background-image: -webkit-linear-gradient(top, #eeeeee, #dddddd);
background-image: -o-linear-gradient(top, #eeeeee, #dddddd);
background-image: linear-gradient(top, #eeeeee, #dddddd);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#dddddd', GradientType=0);
color: #404040;
text-decoration: none;
-webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.025), inset 0 -1px rgba(0, 0, 0, 0.025);
-moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.025), inset 0 -1px rgba(0, 0, 0, 0.025);
box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.025), inset 0 -1px rgba(0, 0, 0, 0.025);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Copyright jQuery Foundation and other contributors, https://jquery.org/
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/jquery/jquery-ui
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
Copyright and related rights for sample code are waived via CC0. Sample
code is defined as all source code contained within the demos directory.
CC0: http://creativecommons.org/publicdomain/zero/1.0/
====
All files located in the node_modules and external directories are
externally maintained libraries used by this software which have their
own licenses; we recommend you read them, as their terms may differ from
the terms above.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"name": "jquery-ui",
"title": "jQuery UI",
"description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.",
"version": "1.12.1",
"homepage": "http://jqueryui.com",
"author": {
"name": "jQuery Foundation and other contributors",
"url": "https://github.com/jquery/jquery-ui/blob/1.12.1/AUTHORS.txt"
},
"main": "ui/widget.js",
"maintainers": [
{
"name": "Scott González",
"email": "scott.gonzalez@gmail.com",
"url": "http://scottgonzalez.com"
},
{
"name": "Jörn Zaefferer",
"email": "joern.zaefferer@gmail.com",
"url": "http://bassistance.de"
},
{
"name": "Mike Sherov",
"email": "mike.sherov@gmail.com",
"url": "http://mike.sherov.com"
},
{
"name": "TJ VanToll",
"email": "tj.vantoll@gmail.com",
"url": "http://tjvantoll.com"
},
{
"name": "Felix Nagel",
"email": "info@felixnagel.com",
"url": "http://www.felixnagel.com"
},
{
"name": "Alex Schmitz",
"email": "arschmitz@gmail.com",
"url": "https://github.com/arschmitz"
}
],
"repository": {
"type": "git",
"url": "git://github.com/jquery/jquery-ui.git"
},
"bugs": "https://bugs.jqueryui.com/",
"license": "MIT",
"scripts": {
"test": "grunt"
},
"dependencies": {},
"devDependencies": {
"commitplease": "2.3.0",
"grunt": "0.4.5",
"grunt-bowercopy": "1.2.4",
"grunt-cli": "0.1.13",
"grunt-compare-size": "0.4.0",
"grunt-contrib-concat": "0.5.1",
"grunt-contrib-csslint": "0.5.0",
"grunt-contrib-jshint": "0.12.0",
"grunt-contrib-qunit": "1.0.1",
"grunt-contrib-requirejs": "0.4.4",
"grunt-contrib-uglify": "0.11.1",
"grunt-git-authors": "3.1.0",
"grunt-html": "6.0.0",
"grunt-jscs": "2.1.0",
"load-grunt-tasks": "3.4.0",
"rimraf": "2.5.1",
"testswarm": "1.1.0"
},
"keywords": []
}
This diff is collapsed.
/** Abstract base class for collection plugins v1.0.1.
Written by Keith Wood (kbwood{at}iinet.com.au) December 2013.
Licensed under the MIT (http://keith-wood.name/licence.html) license. */
(function(){var j=false;window.JQClass=function(){};JQClass.classes={};JQClass.extend=function extender(f){var g=this.prototype;j=true;var h=new this();j=false;for(var i in f){h[i]=typeof f[i]=='function'&&typeof g[i]=='function'?(function(d,e){return function(){var b=this._super;this._super=function(a){return g[d].apply(this,a||[])};var c=e.apply(this,arguments);this._super=b;return c}})(i,f[i]):f[i]}function JQClass(){if(!j&&this._init){this._init.apply(this,arguments)}}JQClass.prototype=h;JQClass.prototype.constructor=JQClass;JQClass.extend=extender;return JQClass}})();(function($){JQClass.classes.JQPlugin=JQClass.extend({name:'plugin',defaultOptions:{},regionalOptions:{},_getters:[],_getMarker:function(){return'is-'+this.name},_init:function(){$.extend(this.defaultOptions,(this.regionalOptions&&this.regionalOptions[''])||{});var c=camelCase(this.name);$[c]=this;$.fn[c]=function(a){var b=Array.prototype.slice.call(arguments,1);if($[c]._isNotChained(a,b)){return $[c][a].apply($[c],[this[0]].concat(b))}return this.each(function(){if(typeof a==='string'){if(a[0]==='_'||!$[c][a]){throw'Unknown method: '+a;}$[c][a].apply($[c],[this].concat(b))}else{$[c]._attach(this,a)}})}},setDefaults:function(a){$.extend(this.defaultOptions,a||{})},_isNotChained:function(a,b){if(a==='option'&&(b.length===0||(b.length===1&&typeof b[0]==='string'))){return true}return $.inArray(a,this._getters)>-1},_attach:function(a,b){a=$(a);if(a.hasClass(this._getMarker())){return}a.addClass(this._getMarker());b=$.extend({},this.defaultOptions,this._getMetadata(a),b||{});var c=$.extend({name:this.name,elem:a,options:b},this._instSettings(a,b));a.data(this.name,c);this._postAttach(a,c);this.option(a,b)},_instSettings:function(a,b){return{}},_postAttach:function(a,b){},_getMetadata:function(d){try{var f=d.data(this.name.toLowerCase())||'';f=f.replace(/'/g,'"');f=f.replace(/([a-zA-Z0-9]+):/g,function(a,b,i){var c=f.substring(0,i).match(/"/g);return(!c||c.length%2===0?'"'+b+'":':b+':')});f=$.parseJSON('{'+f+'}');for(var g in f){var h=f[g];if(typeof h==='string'&&h.match(/^new Date\((.*)\)$/)){f[g]=eval(h)}}return f}catch(e){return{}}},_getInst:function(a){return $(a).data(this.name)||{}},option:function(a,b,c){a=$(a);var d=a.data(this.name);if(!b||(typeof b==='string'&&c==null)){var e=(d||{}).options;return(e&&b?e[b]:e)}if(!a.hasClass(this._getMarker())){return}var e=b||{};if(typeof b==='string'){e={};e[b]=c}this._optionsChanged(a,d,e);$.extend(d.options,e)},_optionsChanged:function(a,b,c){},destroy:function(a){a=$(a);if(!a.hasClass(this._getMarker())){return}this._preDestroy(a,this._getInst(a));a.removeData(this.name).removeClass(this._getMarker())},_preDestroy:function(a,b){}});function camelCase(c){return c.replace(/-([a-z])/g,function(a,b){return b.toUpperCase()})}$.JQPlugin={createPlugin:function(a,b){if(typeof a==='object'){b=a;a='JQPlugin'}a=camelCase(a);var c=camelCase(b.name);JQClass.classes[c]=JQClass.classes[a].extend(b);new JQClass.classes[c]()}}})(jQuery);
\ No newline at end of file
/* Real Person jQuery plugin styles v2.0.1. */
.realperson-challenge {
display: block;
color: #000;
}
.realperson-text {
font-family: "Courier New",monospace !important;
font-size: 6px;
font-weight: bold;
letter-spacing: -1px;
line-height: 3px;
}
.realperson-regen {
padding-top: 4px;
font-size: 12px;
text-align: center;
cursor: pointer;
}
.realperson-disabled {
opacity: 0.5;
filter: Alpha(Opacity=50);
}
.realperson-disabled .realperson-regen {
cursor: default;
}
package jquery;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* RealPerson submission processing.
*/
public class RealPerson extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (rpHash(request.getParameter("defaultReal")).equals(
request.getParameter("defaultRealHash"))) {
// Accepted
}
else {
// Rejected
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
/**
* Compute the hash value to check for "real person" submission.
*
* @param value the entered value
* @return its hash value
*/
private String rpHash(String value) {
int hash = 5381;
value = value.toUpperCase();
for(int i = 0; i < value.length(); i++) {
hash = ((hash << 5) + hash) + value.charAt(i);
}
return String.valueOf(hash);
}
}
/* http://keith-wood.name/realPerson.html
Real Person Form Submission for jQuery v2.0.1.
Written by Keith Wood (kwood{at}iinet.com.au) June 2009.
Available under the MIT (http://keith-wood.name/licence.html) license.
Please attribute the author if you use it. */
(function($) { // Hide scope, no $ conflict
var pluginName = 'realperson';
var ALPHABETIC = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var ALPHANUMERIC = ALPHABETIC + '0123456789';
var DOTS = [
[' * ', ' * * ', ' * * ', ' * * ', ' ***** ', '* *', '* *'],
['****** ', '* *', '* *', '****** ', '* *', '* *', '****** '],
[' ***** ', '* *', '* ', '* ', '* ', '* *', ' ***** '],
['****** ', '* *', '* *', '* *', '* *', '* *', '****** '],
['*******', '* ', '* ', '**** ', '* ', '* ', '*******'],
['*******', '* ', '* ', '**** ', '* ', '* ', '* '],
[' ***** ', '* *', '* ', '* ', '* ***', '* *', ' ***** '],
['* *', '* *', '* *', '*******', '* *', '* *', '* *'],
['*******', ' * ', ' * ', ' * ', ' * ', ' * ', '*******'],
[' *', ' *', ' *', ' *', ' *', '* *', ' ***** '],
['* *', '* ** ', '* ** ', '** ', '* ** ', '* ** ', '* *'],
['* ', '* ', '* ', '* ', '* ', '* ', '*******'],
['* *', '** **', '* * * *', '* * *', '* *', '* *', '* *'],
['* *', '** *', '* * *', '* * *', '* * *', '* **', '* *'],
[' ***** ', '* *', '* *', '* *', '* *', '* *', ' ***** '],
['****** ', '* *', '* *', '****** ', '* ', '* ', '* '],
[' ***** ', '* *', '* *', '* *', '* * *', '* * ', ' **** *'],
['****** ', '* *', '* *', '****** ', '* * ', '* * ', '* *'],
[' ***** ', '* *', '* ', ' ***** ', ' *', '* *', ' ***** '],
['*******', ' * ', ' * ', ' * ', ' * ', ' * ', ' * '],
['* *', '* *', '* *', '* *', '* *', '* *', ' ***** '],
['* *', '* *', ' * * ', ' * * ', ' * * ', ' * * ', ' * '],
['* *', '* *', '* *', '* * *', '* * * *', '** **', '* *'],
['* *', ' * * ', ' * * ', ' * ', ' * * ', ' * * ', '* *'],
['* *', ' * * ', ' * * ', ' * ', ' * ', ' * ', ' * '],
['*******', ' * ', ' * ', ' * ', ' * ', ' * ', '*******'],
[' *** ', ' * * ', '* * *', '* * *', '* * *', ' * * ', ' *** '],
[' * ', ' ** ', ' * * ', ' * ', ' * ', ' * ', '*******'],
[' ***** ', '* *', ' *', ' * ', ' ** ', ' ** ', '*******'],
[' ***** ', '* *', ' *', ' ** ', ' *', '* *', ' ***** '],
[' * ', ' ** ', ' * * ', ' * * ', '*******', ' * ', ' * '],
['*******', '* ', '****** ', ' *', ' *', '* *', ' ***** '],
[' **** ', ' * ', '* ', '****** ', '* *', '* *', ' ***** '],
['*******', ' * ', ' * ', ' * ', ' * ', ' * ', '* '],
[' ***** ', '* *', '* *', ' ***** ', '* *', '* *', ' ***** '],
[' ***** ', '* *', '* *', ' ******', ' *', ' * ', ' **** ']];
/** Create the real person plugin.
<p>Displays a challenge to confirm that the viewer is a real person.</p>
<p>Expects HTML like:</p>
<pre>&lt;input...></pre>
<p>Provide inline configuration like:</p>
<pre>&lt;input data-realperson="name: 'value'">...></pre>
@module RealPerson
@augments JQPlugin
@example $(selector).realperson()
$(selector).realperson({length: 200, toggle: false}) */
$.JQPlugin.createPlugin({
/** The name of the plugin. */
name: pluginName,
/** The set of alphabetic characters. */
alphabetic: ALPHABETIC,
/** The set of alphabetic and numeric characters. */
alphanumeric: ALPHANUMERIC,
/** The set dots that make up each character. */
defaultDots: DOTS,
/** More/less change callback.
Triggered when the more/less button is clicked.
@callback changeCallback
@param expanding {boolean} True if expanding the text, false if collapsing. */
/** Default settings for the plugin.
@property [length=6] {number} Number of characters to use.
@property [regenerate='Click to change'] {string} Instruction text to regenerate.
@property [hashName='{n}Hash'] {string} Name of the hash value field to compare with,
use {n} to substitute with the original field name.
@property [dot='*'] {string} The character to use for the dot patterns.
@property [dots=defaultDots] {string[][]} The dot patterns per letter in chars.
@property [chars=alphabetic] {string} The characters allowed. */
defaultOptions: {
length: 6,
regenerate: 'Click to change',
hashName: '{n}Hash',
dot: '*',
dots: DOTS,
chars: ALPHABETIC
},
_getters: ['getHash'],
_challengeClass: pluginName + '-challenge',
_disabledClass: pluginName + '-disabled',
_hashClass: pluginName + '-hash',
_regenerateClass: pluginName + '-regen',
_textClass: pluginName + '-text',
_optionsChanged: function(elem, inst, options) {
$.extend(inst.options, options);
var text = '';
for (var i = 0; i < inst.options.length; i++) {
text += inst.options.chars.charAt(Math.floor(Math.random() * inst.options.chars.length));
}
inst.hash = hash(text + salt);
var self = this;
elem.closest('form').off('.' + inst.name).
on('submit.' + inst.name, function() {
var name = inst.options.hashName.replace(/\{n\}/, elem.attr('name'));
var form = $(this);
form.find('input[name="' + name + '"]').remove();
form.append('<input type="hidden" class="' + self._hashClass + '" name="' + name +
'" value="' + hash(text + salt) + '">');
setTimeout(function() {
form.find('input[name="' + name + '"]').remove();
}, 0);
});
elem.prevAll('.' + this._challengeClass + ',.' + this._hashClass).remove().end().
before(this._generateHTML(inst, text)).
prevAll('div.' + this._challengeClass).click(function() {
if (!$(this).hasClass(self._disabledClass)) {
elem.realperson('option', {});
}
});
},
/* Enable the plugin functionality for a control.
@param elem {element} The control to affect. */
enable: function(elem) {
elem = $(elem);
if (!elem.hasClass(this._getMarker())) {
return;
}
elem.removeClass(this._disabledClass).prop('disabled', false).
prevAll('.' + this._challengeClass).removeClass(this._disabledClass);
},
/* Disable the plugin functionality for a control.
@param elem {element} The control to affect. */
disable: function(elem) {
elem = $(elem);
if (!elem.hasClass(this._getMarker())) {
return;
}
elem.addClass(this._disabledClass).prop('disabled', true).
prevAll('.' + this._challengeClass).addClass(this._disabledClass);
},
/* Retrieve the hash value.
@param elem {Element} The control with the hash.
@return {number} The hash value. */
getHash: function(elem) {
var inst = this._getInst(elem);
// console.log("inst", inst)
return inst ? inst.hash : 0;
},
/* Generate the additional content for this control.
@param inst {object} The current instance settings.
@param text {string} The text to display.
@return {string} The additional content. */
_generateHTML: function(inst, text) {
var html = '<div class="' + this._challengeClass + '">' +
'<div class="' + this._textClass + '">';
for (var i = 0; i < inst.options.dots[0].length; i++) {
for (var j = 0; j < text.length; j++) {
html += inst.options.dots[inst.options.chars.indexOf(text.charAt(j))][i].
replace(/ /g, '&#160;').replace(/\*/g, inst.options.dot) +
'&#160;&#160;';
}
html += '<br>';
}
html += '</div><div class="' + this._regenerateClass + '">' +
inst.options.regenerate + '</div></div>';
return html;
},
_preDestroy: function(elem, inst) {
elem.closest('form').off('.' + inst.name);
elem.prevAll('.' + this._challengeClass + ',.' + this._hashClass).remove();
}
});
/* Load salt value and clear. */
var salt = $.salt || '#salt';
delete $.salt;
$(function() {
var saltElem = $(salt);
if (saltElem.length) {
salt = saltElem.text();
saltElem.remove();
}
if (salt === '#salt') {
salt = '';
}
});
/* Compute a hash value for the given text.
@param value {string} The text to hash.
@return {number} The corresponding hash value. */
function hash(value) {
// dbg
// console.log("original value:", value)
var hash = 5381;
for (var i = 0; i < value.length; i++) {
hash = ((hash << 5) + hash) + value.charCodeAt(i);
// dbg
// console.log(i, hash)
}
// dbg
// console.log("hashed value:", hash)
return hash;
}
})(jQuery);
// console.log("loaded realperson")
/* http://keith-wood.name/realPerson.html
Real Person Form Submission for jQuery v2.0.1.
Written by Keith Wood (kwood{at}iinet.com.au) June 2009.
Available under the MIT (http://keith-wood.name/licence.html) license.
Please attribute the author if you use it. */
(function($){var h='realperson';var k='ABCDEFGHIJKLMNOPQRSTUVWXYZ';var l=k+'0123456789';var m=[[' * ',' * * ',' * * ',' * * ',' ***** ','* *','* *'],['****** ','* *','* *','****** ','* *','* *','****** '],[' ***** ','* *','* ','* ','* ','* *',' ***** '],['****** ','* *','* *','* *','* *','* *','****** '],['*******','* ','* ','**** ','* ','* ','*******'],['*******','* ','* ','**** ','* ','* ','* '],[' ***** ','* *','* ','* ','* ***','* *',' ***** '],['* *','* *','* *','*******','* *','* *','* *'],['*******',' * ',' * ',' * ',' * ',' * ','*******'],[' *',' *',' *',' *',' *','* *',' ***** '],['* *','* ** ','* ** ','** ','* ** ','* ** ','* *'],['* ','* ','* ','* ','* ','* ','*******'],['* *','** **','* * * *','* * *','* *','* *','* *'],['* *','** *','* * *','* * *','* * *','* **','* *'],[' ***** ','* *','* *','* *','* *','* *',' ***** '],['****** ','* *','* *','****** ','* ','* ','* '],[' ***** ','* *','* *','* *','* * *','* * ',' **** *'],['****** ','* *','* *','****** ','* * ','* * ','* *'],[' ***** ','* *','* ',' ***** ',' *','* *',' ***** '],['*******',' * ',' * ',' * ',' * ',' * ',' * '],['* *','* *','* *','* *','* *','* *',' ***** '],['* *','* *',' * * ',' * * ',' * * ',' * * ',' * '],['* *','* *','* *','* * *','* * * *','** **','* *'],['* *',' * * ',' * * ',' * ',' * * ',' * * ','* *'],['* *',' * * ',' * * ',' * ',' * ',' * ',' * '],['*******',' * ',' * ',' * ',' * ',' * ','*******'],[' *** ',' * * ','* * *','* * *','* * *',' * * ',' *** '],[' * ',' ** ',' * * ',' * ',' * ',' * ','*******'],[' ***** ','* *',' *',' * ',' ** ',' ** ','*******'],[' ***** ','* *',' *',' ** ',' *','* *',' ***** '],[' * ',' ** ',' * * ',' * * ','*******',' * ',' * '],['*******','* ','****** ',' *',' *','* *',' ***** '],[' **** ',' * ','* ','****** ','* *','* *',' ***** '],['*******',' * ',' * ',' * ',' * ',' * ','* '],[' ***** ','* *','* *',' ***** ','* *','* *',' ***** '],[' ***** ','* *','* *',' ******',' *',' * ',' **** ']];$.JQPlugin.createPlugin({name:h,alphabetic:k,alphanumeric:l,defaultDots:m,defaultOptions:{length:6,regenerate:'Click to change',hashName:'{n}Hash',dot:'*',dots:m,chars:k},_getters:['getHash'],_challengeClass:h+'-challenge',_disabledClass:h+'-disabled',_hashClass:h+'-hash',_regenerateClass:h+'-regen',_textClass:h+'-text',_optionsChanged:function(c,d,e){$.extend(d.options,e);var f='';for(var i=0;i<d.options.length;i++){f+=d.options.chars.charAt(Math.floor(Math.random()*d.options.chars.length))}d.hash=hash(f+n);var g=this;c.closest('form').off('.'+d.name).on('submit.'+d.name,function(){var a=d.options.hashName.replace(/\{n\}/,c.attr('name'));var b=$(this);b.find('input[name="'+a+'"]').remove();b.append('<input type="hidden" class="'+g._hashClass+'" name="'+a+'" value="'+hash(f+n)+'">');setTimeout(function(){b.find('input[name="'+a+'"]').remove()},0)});c.prevAll('.'+this._challengeClass+',.'+this._hashClass).remove().end().before(this._generateHTML(d,f)).prevAll('div.'+this._challengeClass).click(function(){if(!$(this).hasClass(g._disabledClass)){c.realperson('option',{})}})},enable:function(a){a=$(a);if(!a.hasClass(this._getMarker())){return}a.removeClass(this._disabledClass).prop('disabled',false).prevAll('.'+this._challengeClass).removeClass(this._disabledClass)},disable:function(a){a=$(a);if(!a.hasClass(this._getMarker())){return}a.addClass(this._disabledClass).prop('disabled',true).prevAll('.'+this._challengeClass).addClass(this._disabledClass)},getHash:function(a){var b=this._getInst(a);return b?b.hash:0},_generateHTML:function(a,b){var c='<div class="'+this._challengeClass+'">'+'<div class="'+this._textClass+'">';for(var i=0;i<a.options.dots[0].length;i++){for(var j=0;j<b.length;j++){c+=a.options.dots[a.options.chars.indexOf(b.charAt(j))][i].replace(/ /g,'&#160;').replace(/\*/g,a.options.dot)+'&#160;&#160;'}c+='<br>'}c+='</div><div class="'+this._regenerateClass+'">'+a.options.regenerate+'</div></div>';return c},_preDestroy:function(a,b){a.closest('form').off('.'+b.name);a.prevAll('.'+this._challengeClass+',.'+this._hashClass).remove()}});var n=$.salt||'#salt';delete $.salt;$(function(){var a=$(n);if(a.length){n=a.text();a.remove()}if(n==='#salt'){n=''}});function hash(a){var b=5381;for(var i=0;i<a.length;i++){b=((b<<5)+b)+a.charCodeAt(i)}return b}})(jQuery);
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Jinja templates
===============
Simple html templates for jinja2
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment