diff --git a/static/google-code-prettify/run_prettify.js b/static/google-code-prettify/run_prettify.js
new file mode 100644
index 0000000000000000000000000000000000000000..e3d9a9c298b7a1c2bea03993c65454fa89f64de1
--- /dev/null
+++ b/static/google-code-prettify/run_prettify.js
@@ -0,0 +1,34 @@
+!function(){var r=null;
+(function(){function X(e){function j(){try{J.doScroll("left")}catch(e){P(j,50);return}w("poll")}function w(j){if(!(j.type=="readystatechange"&&x.readyState!="complete")&&((j.type=="load"?n:x)[z](i+j.type,w,!1),!m&&(m=!0)))e.call(n,j.type||j)}var Y=x.addEventListener,m=!1,C=!0,t=Y?"addEventListener":"attachEvent",z=Y?"removeEventListener":"detachEvent",i=Y?"":"on";if(x.readyState=="complete")e.call(n,"lazy");else{if(x.createEventObject&&J.doScroll){try{C=!n.frameElement}catch(A){}C&&j()}x[t](i+"DOMContentLoaded",
+w,!1);x[t](i+"readystatechange",w,!1);n[t](i+"load",w,!1)}}function Q(){S&&X(function(){var e=K.length;$(e?function(){for(var j=0;j<e;++j)(function(e){P(function(){n.exports[K[e]].apply(n,arguments)},0)})(j)}:void 0)})}for(var n=window,P=n.setTimeout,x=document,J=x.documentElement,L=x.head||x.getElementsByTagName("head")[0]||J,z="",A=x.getElementsByTagName("script"),m=A.length;--m>=0;){var M=A[m],T=M.src.match(/^[^#?]*\/run_prettify\.js(\?[^#]*)?(?:#.*)?$/);if(T){z=T[1]||"";M.parentNode.removeChild(M);
+break}}var S=!0,D=[],N=[],K=[];z.replace(/[&?]([^&=]+)=([^&]+)/g,function(e,j,w){w=decodeURIComponent(w);j=decodeURIComponent(j);j=="autorun"?S=!/^[0fn]/i.test(w):j=="lang"?D.push(w):j=="skin"?N.push(w):j=="callback"&&K.push(w)});m=0;for(z=D.length;m<z;++m)(function(){var e=x.createElement("script");e.onload=e.onerror=e.onreadystatechange=function(){if(e&&(!e.readyState||/loaded|complete/.test(e.readyState)))e.onerror=e.onload=e.onreadystatechange=r,--R,R||P(Q,0),e.parentNode&&e.parentNode.removeChild(e),
+e=r};e.type="text/javascript";e.src="https://google-code-prettify.googlecode.com/svn/loader/lang-"+encodeURIComponent(D[m])+".js";L.insertBefore(e,L.firstChild)})(D[m]);for(var R=D.length,A=[],m=0,z=N.length;m<z;++m)A.push("https://google-code-prettify.googlecode.com/svn/loader/skins/"+encodeURIComponent(N[m])+".css");A.push("https://google-code-prettify.googlecode.com/svn/loader/prettify.css");(function(e){function j(m){if(m!==w){var n=x.createElement("link");n.rel="stylesheet";n.type="text/css";
+if(m+1<w)n.error=n.onerror=function(){j(m+1)};n.href=e[m];L.appendChild(n)}}var w=e.length;j(0)})(A);var $=function(){window.PR_SHOULD_USE_CONTINUATION=!0;var e;(function(){function j(a){function d(f){var b=f.charCodeAt(0);if(b!==92)return b;var a=f.charAt(1);return(b=i[a])?b:"0"<=a&&a<="7"?parseInt(f.substring(1),8):a==="u"||a==="x"?parseInt(f.substring(2),16):f.charCodeAt(1)}function h(f){if(f<32)return(f<16?"\\x0":"\\x")+f.toString(16);f=String.fromCharCode(f);return f==="\\"||f==="-"||f==="]"||
+f==="^"?"\\"+f:f}function b(f){var b=f.substring(1,f.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),f=[],a=b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,g=b.length;a<g;++a){var k=b[a];if(/\\[bdsw]/i.test(k))c.push(k);else{var k=d(k),o;a+2<g&&"-"===b[a+1]?(o=d(b[a+2]),a+=2):o=k;f.push([k,o]);o<65||k>122||(o<65||k>90||f.push([Math.max(65,k)|32,Math.min(o,90)|32]),o<97||k>122||f.push([Math.max(97,k)&-33,Math.min(o,122)&-33]))}}f.sort(function(f,
+a){return f[0]-a[0]||a[1]-f[1]});b=[];g=[];for(a=0;a<f.length;++a)k=f[a],k[0]<=g[1]+1?g[1]=Math.max(g[1],k[1]):b.push(g=k);for(a=0;a<b.length;++a)k=b[a],c.push(h(k[0])),k[1]>k[0]&&(k[1]+1>k[0]&&c.push("-"),c.push(h(k[1])));c.push("]");return c.join("")}function e(f){for(var a=f.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],g=0,k=0;g<c;++g){var o=a[g];o==="("?++k:"\\"===o.charAt(0)&&(o=+o.substring(1))&&(o<=k?
+d[o]=-1:a[g]=h(o))}for(g=1;g<d.length;++g)-1===d[g]&&(d[g]=++j);for(k=g=0;g<c;++g)o=a[g],o==="("?(++k,d[k]||(a[g]="(?:")):"\\"===o.charAt(0)&&(o=+o.substring(1))&&o<=k&&(a[g]="\\"+d[o]);for(g=0;g<c;++g)"^"===a[g]&&"^"!==a[g+1]&&(a[g]="");if(f.ignoreCase&&F)for(g=0;g<c;++g)o=a[g],f=o.charAt(0),o.length>=2&&f==="["?a[g]=b(o):f!=="\\"&&(a[g]=o.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var j=0,F=!1,l=!1,I=0,c=a.length;I<c;++I){var p=
+a[I];if(p.ignoreCase)l=!0;else if(/[a-z]/i.test(p.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){F=!0;l=!1;break}}for(var i={b:8,t:9,n:10,v:11,f:12,r:13},q=[],I=0,c=a.length;I<c;++I){p=a[I];if(p.global||p.multiline)throw Error(""+p);q.push("(?:"+e(p)+")")}return RegExp(q.join("|"),l?"gi":"g")}function m(a,d){function h(a){var c=a.nodeType;if(c==1){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)h(c);c=a.nodeName.toLowerCase();if("br"===c||"li"===c)e[l]="\n",F[l<<1]=j++,
+F[l++<<1|1]=a}}else if(c==3||c==4)c=a.nodeValue,c.length&&(c=d?c.replace(/\r\n?/g,"\n"):c.replace(/[\t\n\r ]+/g," "),e[l]=c,F[l<<1]=j,j+=c.length,F[l++<<1|1]=a)}var b=/(?:^|\s)nocode(?:\s|$)/,e=[],j=0,F=[],l=0;h(a);return{a:e.join("").replace(/\n$/,""),d:F}}function n(a,d,h,b){d&&(a={a:d,e:a},h(a),b.push.apply(b,a.g))}function x(a){for(var d=void 0,h=a.firstChild;h;h=h.nextSibling)var b=h.nodeType,d=b===1?d?a:h:b===3?S.test(h.nodeValue)?a:d:d;return d===a?void 0:d}function C(a,d){function h(a){for(var l=
+a.e,j=[l,"pln"],c=0,p=a.a.match(e)||[],m={},q=0,f=p.length;q<f;++q){var B=p[q],y=m[B],u=void 0,g;if(typeof y==="string")g=!1;else{var k=b[B.charAt(0)];if(k)u=B.match(k[1]),y=k[0];else{for(g=0;g<i;++g)if(k=d[g],u=B.match(k[1])){y=k[0];break}u||(y="pln")}if((g=y.length>=5&&"lang-"===y.substring(0,5))&&!(u&&typeof u[1]==="string"))g=!1,y="src";g||(m[B]=y)}k=c;c+=B.length;if(g){g=u[1];var o=B.indexOf(g),H=o+g.length;u[2]&&(H=B.length-u[2].length,o=H-g.length);y=y.substring(5);n(l+k,B.substring(0,o),h,
+j);n(l+k+o,g,A(y,g),j);n(l+k+H,B.substring(H),h,j)}else j.push(l+k,y)}a.g=j}var b={},e;(function(){for(var h=a.concat(d),l=[],i={},c=0,p=h.length;c<p;++c){var m=h[c],q=m[3];if(q)for(var f=q.length;--f>=0;)b[q.charAt(f)]=m;m=m[1];q=""+m;i.hasOwnProperty(q)||(l.push(m),i[q]=r)}l.push(/[\S\s]/);e=j(l)})();var i=d.length;return h}function t(a){var d=[],h=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,
+r,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,r,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,r,"\"'"]);a.verbatimStrings&&h.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,r]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,r,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,
+r,"#"]),h.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,r])):d.push(["com",/^#[^\n\r]*/,r,"#"]));a.cStyleComments&&(h.push(["com",/^\/\/[^\n\r]*/,r]),h.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,r]));if(b=a.regexLiterals){var e=(b=b>1?"":"\n\r")?".":"[\\S\\s]";h.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+
+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+e+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+e+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&h.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&h.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),r]);d.push(["pln",/^\s+/,r," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");h.push(["lit",/^@[$_a-z][\w$@]*/i,r],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,r],["pln",/^[$_a-z][\w$@]*/i,r],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,
+r,"0123456789"],["pln",/^\\[\S\s]?/,r],["pun",RegExp(b),r]);return C(d,h)}function z(a,d,h){function b(a){var c=a.nodeType;if(c==1&&!j.test(a.className))if("br"===a.nodeName)e(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&h){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(l.createTextNode(d),a.nextSibling),e(a),c||a.parentNode.removeChild(a)}}
+function e(a){function b(a,c){var d=c?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),h=a.nextSibling;f.appendChild(d);for(var e=h;e;e=h)h=e.nextSibling,f.appendChild(e)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var j=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,l=a.ownerDocument,i=l.createElement("li");a.firstChild;)i.appendChild(a.firstChild);for(var c=[i],p=0;p<c.length;++p)b(c[p]);d===(d|0)&&c[0].setAttribute("value",
+d);var n=l.createElement("ol");n.className="linenums";for(var d=Math.max(0,d-1|0)||0,p=0,q=c.length;p<q;++p)i=c[p],i.className="L"+(p+d)%10,i.firstChild||i.appendChild(l.createTextNode("\u00a0")),n.appendChild(i);a.appendChild(n)}function i(a,d){for(var h=d.length;--h>=0;){var b=d[h];U.hasOwnProperty(b)?V.console&&console.warn("cannot override language handler %s",b):U[b]=a}}function A(a,d){if(!a||!U.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return U[a]}function D(a){var d=
+a.h;try{var h=m(a.c,a.i),b=h.a;a.a=b;a.d=h.d;a.e=0;A(d,b)(a);var e=/\bMSIE\s(\d+)/.exec(navigator.userAgent),e=e&&+e[1]<=8,d=/\n/g,i=a.a,j=i.length,h=0,l=a.d,n=l.length,b=0,c=a.g,p=c.length,t=0;c[p]=j;var q,f;for(f=q=0;f<p;)c[f]!==c[f+2]?(c[q++]=c[f++],c[q++]=c[f++]):f+=2;p=q;for(f=q=0;f<p;){for(var x=c[f],y=c[f+1],u=f+2;u+2<=p&&c[u+1]===y;)u+=2;c[q++]=x;c[q++]=y;f=u}c.length=q;var g=a.c,k;if(g)k=g.style.display,g.style.display="none";try{for(;b<n;){var o=l[b+2]||j,H=c[t+2]||j,u=Math.min(o,H),E=l[b+
+1],W;if(E.nodeType!==1&&(W=i.substring(h,u))){e&&(W=W.replace(d,"\r"));E.nodeValue=W;var Z=E.ownerDocument,s=Z.createElement("span");s.className=c[t+1];var z=E.parentNode;z.replaceChild(s,E);s.appendChild(E);h<o&&(l[b+1]=E=Z.createTextNode(i.substring(u,o)),z.insertBefore(E,s.nextSibling))}h=u;h>=o&&(b+=2);h>=H&&(t+=2)}}finally{if(g)g.style.display=k}}catch(v){V.console&&console.log(v&&v.stack||v)}}var V=window,G=["break,continue,do,else,for,if,return,while"],O=[[G,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
+"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],J=[O,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],K=[O,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],
+L=[K,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],O=[O,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],M=[G,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
+N=[G,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],R=[G,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],G=[G,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],Q=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
+S=/\S/,T=t({keywords:[J,L,O,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",M,N,G],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),U={};i(T,["default-code"]);i(C([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
+/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);i(C([["pln",/^\s+/,r," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,r,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],
+["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);i(C([],[["atv",/^[\S\s]+/]]),["uq.val"]);i(t({keywords:J,hashComments:!0,cStyleComments:!0,types:Q}),["c","cc","cpp","cxx","cyc","m"]);i(t({keywords:"null,true,false"}),["json"]);i(t({keywords:L,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:Q}),
+["cs"]);i(t({keywords:K,cStyleComments:!0}),["java"]);i(t({keywords:G,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);i(t({keywords:M,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);i(t({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);i(t({keywords:N,
+hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);i(t({keywords:O,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);i(t({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);i(t({keywords:R,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]);
+i(C([],[["str",/^[\S\s]+/]]),["regex"]);var X=V.PR={createSimpleLexer:C,registerLangHandler:i,sourceDecorator:t,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:function(a,d,e){var b=document.createElement("div");b.innerHTML="<pre>"+a+"</pre>";b=b.firstChild;e&&z(b,e,!0);D({h:d,j:e,c:b,i:1});return b.innerHTML},
+prettyPrint:e=e=function(a,d){function e(){for(var b=V.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;p<j.length&&c.now()<b;p++){for(var d=j[p],m=k,l=d;l=l.previousSibling;){var n=l.nodeType,s=(n===7||n===8)&&l.nodeValue;if(s?!/^\??prettify\b/.test(s):n!==3||/\S/.test(l.nodeValue))break;if(s){m={};s.replace(/\b(\w+)=([\w%+\-.:]+)/g,function(a,b,c){m[b]=c});break}}l=d.className;if((m!==k||f.test(l))&&!w.test(l)){n=!1;for(s=d.parentNode;s;s=s.parentNode)if(g.test(s.tagName)&&s.className&&f.test(s.className)){n=
+!0;break}if(!n){d.className+=" prettyprinted";n=m.lang;if(!n){var n=l.match(q),A;if(!n&&(A=x(d))&&u.test(A.tagName))n=A.className.match(q);n&&(n=n[1])}if(y.test(d.tagName))s=1;else var s=d.currentStyle,v=i.defaultView,s=(s=s?s.whiteSpace:v&&v.getComputedStyle?v.getComputedStyle(d,r).getPropertyValue("white-space"):0)&&"pre"===s.substring(0,3);v=m.linenums;if(!(v=v==="true"||+v))v=(v=l.match(/\blinenums\b(?::(\d+))?/))?v[1]&&v[1].length?+v[1]:!0:!1;v&&z(d,v,s);t={h:n,c:d,j:v,i:s};D(t)}}}p<j.length?
+P(e,250):"function"===typeof a&&a()}for(var b=d||document.body,i=b.ownerDocument||document,b=[b.getElementsByTagName("pre"),b.getElementsByTagName("code"),b.getElementsByTagName("xmp")],j=[],m=0;m<b.length;++m)for(var l=0,n=b[m].length;l<n;++l)j.push(b[m][l]);var b=r,c=Date;c.now||(c={now:function(){return+new Date}});var p=0,t,q=/\blang(?:uage)?-([\w.]+)(?!\S)/,f=/\bprettyprint\b/,w=/\bprettyprinted\b/,y=/pre|xmp/i,u=/^code$/i,g=/^(?:pre|code|xmp)$/i,k={};e()}};typeof define==="function"&&define.amd&&
+define("google-code-prettify",[],function(){return X})})();return e}();R||P(Q,0)})();}()
diff --git a/templates/_messages.html b/templates/_messages.html
new file mode 100644
index 0000000000000000000000000000000000000000..4c3e9c5fb40f7cb87f78f103ec415c0b95a79d6c
--- /dev/null
+++ b/templates/_messages.html
@@ -0,0 +1,12 @@
+{% if messages %}
+  <div class="row">
+    <div class="span12">
+      {% for message in messages %}
+	<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}{{message.tags}}{% endif %} fade in">
+	  <a class="close" title="Close" href="#" data-dismiss="alert">&times;</a>
+	  <strong>{{message.tags|title}}:</strong> {{message}}
+	</div>
+      {% endfor %}
+    </div><!-- end span -->
+  </div><!-- end row -->
+{% endif %}
diff --git a/templates/api/base.html b/templates/api/base.html
new file mode 100644
index 0000000000000000000000000000000000000000..8547f0c792f242a88ecb17a90a070245a3c32954
--- /dev/null
+++ b/templates/api/base.html
@@ -0,0 +1,82 @@
+{% extends "base.html" %}
+
+{% block section_title %}API{% endblock %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-lg-3">
+
+    <div class="panel panel-default">
+      <div class="panel-heading">PKS</div>
+      <div class="list-group" style="background-color: #f7f5fa;">
+	<a id="pks_add" href="{{ url_for('pks_add') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Add</a>
+	<a id="pks_lookup" href="{{ url_for('pks_lookup') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Lookup</a>
+	<a id="pks_all" href="{{ url_for('pks_all') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> All</a>
+      </div>
+    </div>
+
+    <div class="panel panel-default">
+      <div class="panel-heading">UCG</div>
+      <div class="list-group" style="background-color: #f7f5fa;">
+	<a id="ucg_pubkey" href="{{ url_for('ucg_pubkey') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Pubkey</a>
+	<a id="ucg_peering" href="{{ url_for('ucg_peering') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Peering</a>
+	<a id="ucg_peering_keys" href="{{ url_for('ucg_peering_keys') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Keys (peering)</a>
+	<a id="ucg_peering_peer" href="{{ url_for('ucg_peering_peer') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Peer (peering)</a>
+	<a id="ucg_peering_peers" href="{{ url_for('ucg_peering_peers') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Peers (peering)</a>
+	<a id="ucg_peering_peers_upstream" href="{{ url_for('ucg_peering_peers_upstream') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Upstream (peering/peers)</a>
+	<a id="ucg_peering_peers_downstream" href="{{ url_for('ucg_peering_peers_downstream') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Downstream (peering/peers)</a>
+	<a id="ucg_peering_forward" href="{{ url_for('ucg_peering_forward') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Forward (peering)</a>
+	<a id="ucg_peering_status" href="{{ url_for('ucg_peering_status') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Status (peering)</a>
+	<a id="ucg_tht" href="{{ url_for('ucg_tht') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> THT</a>
+      </div>
+    </div>
+
+    <div class="panel panel-default">
+      <div class="panel-heading">HDC</div>
+      <div class="list-group" style="background-color: #f7f5fa;">
+	<a id="hdc_amendments_current" href="{{ url_for('hdc_amendments_current') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Current (amendments)</a>
+	<a id="hdc_amendments_current_votes" href="{{ url_for('hdc_amendments_current_votes') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Votes (amendments/current)</a>
+	<a id="hdc_amendments_votes" href="{{ url_for('hdc_amendments_votes') }}" class="list-group-item"><i class="glyphicon glyphicon-minus"></i> Votes (amendments)</a>
+      </div>
+    </div>
+
+  </div>
+  <div class="col-lg-9">
+    {% block sub_content %}{% endblock %}
+  </div>
+</div>
+
+{% endblock %}
+
+{% block foot %}
+    <script src="{{ url_for('static', filename='google-code-prettify/run_prettify.js') }}"></script>
+
+    <script type="text/javascript">
+      $('body').ready(function () {
+        var urls = {
+	  '{{ url_for('pks_add') }}': 'pks_add',
+	  '{{ url_for('pks_lookup') }}': 'pks_lookup',
+	  '{{ url_for('pks_all') }}': 'pks_all',
+
+          '{{ url_for('ucg_pubkey') }}': 'ucg_pubkey',
+          '{{ url_for('ucg_peering') }}': 'ucg_peering',
+          '{{ url_for('ucg_peering_keys') }}': 'ucg_peering_keys',
+          '{{ url_for('ucg_peering_peer') }}': 'ucg_peering_peer',
+          '{{ url_for('ucg_peering_peers') }}': 'ucg_peering_peers',
+          '{{ url_for('ucg_peering_peers_upstream') }}': 'ucg_peering_peers_upstream',
+          '{{ url_for('ucg_peering_peers_downstream') }}': 'ucg_peering_peers_downstream',
+          '{{ url_for('ucg_peering_forward') }}': 'ucg_peering_forward',
+          '{{ url_for('ucg_peering_status') }}': 'ucg_peering_status',
+          '{{ url_for('ucg_tht') }}': 'ucg_tht',
+
+          '{{ url_for('hdc_amendments_current') }}': 'hdc_amendments_current',
+          '{{ url_for('hdc_amendments_current_votes') }}': 'hdc_amendments_current_votes',
+          '{{ url_for('hdc_amendments_votes') }}': 'hdc_amendments_votes',
+        };
+
+        var matches = window.location.pathname.match(/^(\/[^?]*)/g);
+        $('#' + urls[matches[0]]).addClass('active');
+      });
+    </script>
+{% endblock %}
diff --git a/templates/api/index.html b/templates/api/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..4d2e358fe86b5fcf8ede0366556337a37c9b9743
--- /dev/null
+++ b/templates/api/index.html
@@ -0,0 +1,9 @@
+{% extends "api/base.html" %}
+
+{% block sub_content %}
+<h1><span class="label label-default">API</span></h1>
+
+<div class="alert alert-info">
+  On the left side, click on the link request you want to test.
+</div>
+{% endblock %}
diff --git a/templates/api/result.html b/templates/api/result.html
new file mode 100644
index 0000000000000000000000000000000000000000..707049268594ddb044b68df1b5f1629fe42b0676
--- /dev/null
+++ b/templates/api/result.html
@@ -0,0 +1,7 @@
+{% extends "api/base.html" %}
+
+{% block sub_content %}
+<h1><span class="label label-default">Result</span></h1>
+
+<pre class="{{style}}">{{result}}</pre>
+{% endblock %}
diff --git a/templates/base.html b/templates/base.html
new file mode 100644
index 0000000000000000000000000000000000000000..2b395c74cbfbf1488c433b281ceadcbcab09dc08
--- /dev/null
+++ b/templates/base.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <title>{% block page_title %}uCoin - {% block section_title %}{% endblock %}{% endblock %}</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <!-- Bootstrap -->
+    <link href="{{ url_for('static', filename='bootstrap/css/bootstrap.min.css') }}" rel="stylesheet" media="screen">
+    <link href="{{ url_for('static', filename='bootstrap/css/bootstrap-theme.min.css') }}" rel="stylesheet" media="screen">
+    <style>body {overflow-y: scroll;}</style>
+
+    <script type="text/javascript">
+      var $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
+    </script>
+
+    {% block head %}{% endblock %}
+  </head>
+  <body>
+    {% include "nav.html" %}
+
+    {% block header %}{% endblock %}
+
+    <div class="{% block content_class %}container{% endblock %}">
+
+      <div role="main">
+	{% include "_messages.html" %}
+	{% block content %}{% endblock %}
+      </div> <!--/main -->
+
+      {% include "footer.html" %}
+
+    </div> <!--/.container -->
+
+    <!-- JavaScript plugins (requires jQuery) -->
+    {#<script src="http://code.jquery.com/jquery.js"></script>#}
+    <script src="{{ url_for('static', filename='jquery/jquery.min.js') }}"></script>
+    <!-- Include all compiled plugins (below), or include individual files as needed -->
+    <script src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js') }}"></script>
+
+    <script type="text/javascript">
+      $('body').ready(function () {
+        var urlMenu = {
+          '/': 'wallets',
+          '{{ url_for('wallets') }}': 'wallets',
+          '{{ url_for('api') }}': 'api',
+        };
+
+        var matches = window.location.pathname.match(/^(\/[^\/]*)/g);
+        $('#' + (urlMenu[matches[0]] ? urlMenu[matches[0]] : urlMenu['/'])).addClass('active');
+      });
+    </script>
+
+    {% block foot %}{% endblock %}
+
+  </body>
+</html>
diff --git a/templates/footer.html b/templates/footer.html
new file mode 100644
index 0000000000000000000000000000000000000000..4f95c25504dfee9c7b26730ea6845acc4f26b9e4
--- /dev/null
+++ b/templates/footer.html
@@ -0,0 +1,18 @@
+<hr/>
+
+{% block footer %}
+  <footer class="footer">
+    <div class="pull-right">
+      {#<a class="tooltip_link" href="http://ask.vegeclic.fr" title="Questions - Réponses"><img src="{% static "ask.png" %}"/></a>
+      <a class="tooltip_link" href="#" title="+33 6 47 78 24 00" alt="+33 6 47 78 24 00"><img src="{% static "telephone.png" %}"/></a>
+      <a class="tooltip_link" href="http://twitter.com/Vegeclic" title="Suivez nous sur twitter"><img src="{% static "twitter.png" %}" /></a>
+      <a class="tooltip_link" href="https://www.facebook.com/Vegeclic" title="Aimez nous sur Facebook"><img src="{% static "facebook.png" %}" /></a>#}
+    </div>
+    <div class="copy">
+      <a class="badge" href="https://github.com/canercandan/ucoin-python-api">ucoin-python-api - version 0.1</a> | Under <a href="http://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License</a>
+    </div>
+    <nav>
+      {% block footernav %}{% endblock %}
+    </nav>
+  </footer>
+{% endblock footer %}
diff --git a/templates/nav.html b/templates/nav.html
new file mode 100644
index 0000000000000000000000000000000000000000..8df7bfd1d63b8f5e10d775605f5ddfc5cea5406b
--- /dev/null
+++ b/templates/nav.html
@@ -0,0 +1,27 @@
+<div class="navbar navbar-default navbar-static-top">
+  <div class="container">
+    <div class="navbar-header">
+      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
+	<span class="icon-bar"></span>
+	<span class="icon-bar"></span>
+	<span class="icon-bar"></span>
+      </button>
+      <a href="#" class="navbar-brand">
+	<span class="label label-default"><strong>uCoin</strong></span>
+      </a>
+    </div>
+    <div class="navbar-collapse collapse">
+      <ul class="nav navbar-nav">
+	<li id="wallets"><a href="{{ url_for('wallets') }}"><i class="glyphicon glyphicon-briefcase"></i> Wallets</a></li>
+	<li id="api"><a href="{{ url_for('api') }}"><i class="glyphicon glyphicon-cog"></i> API</a></li>
+      </ul>
+      <h4 class="navbar-text pull-right">
+	{% if auth %}
+	  <span class="label label-success">signed responses (secure mode)</span>
+	{% else %}
+	  <span class="label label-warning">unsigned responses (fast mode)</span>
+	{% endif %}
+      </h4>
+    </div>
+  </div>
+</div>
diff --git a/templates/wallets/base.html b/templates/wallets/base.html
new file mode 100644
index 0000000000000000000000000000000000000000..8c50ba32bd81a23152494cedb64e41ec070f7217
--- /dev/null
+++ b/templates/wallets/base.html
@@ -0,0 +1,43 @@
+{% extends "base.html" %}
+
+{% block section_title %}Wallets{% endblock %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-lg-3">
+    <div class="list-group" style="background-color: #f7f5fa;">
+      <a id="new" href="{{ url_for('new_wallet') }}" class="list-group-item"><i class="glyphicon glyphicon-plus-sign"></i> New</a>
+      <a id="list" href="{{ url_for('wallets') }}" class="list-group-item"><i class="glyphicon glyphicon-list-alt"></i> Wallet list</a>
+    </div>
+
+    {% if key %}
+    <div class="list-group" style="background-color: #f7f5fa;">
+      <a id="new" href="{{ url_for('new_wallet') }}" class="list-group-item"><i class="glyphicon glyphicon-plus-sign"></i> New</a>
+      <a id="list" href="{{ url_for('wallets') }}" class="list-group-item"><i class="glyphicon glyphicon-list-alt"></i> Wallet list</a>
+    </div>
+    {% endif %}
+  </div>
+  <div class="col-lg-9">
+    {% block sub_content %}{% endblock %}
+  </div>
+</div>
+
+{% endblock %}
+
+{% block foot %}
+    <script type="text/javascript">
+      $('body').ready(function () {
+        var urls = {
+          '/': 'list',
+          '{{ url_for('new_wallet') }}': 'new',
+          '{{ url_for('wallets') }}': 'list',
+        };
+
+        var matches = window.location.pathname.match(/^(\/[^?]*)/g);
+        $('#' + urls[matches[0]]).addClass('active');
+      });
+    </script>
+
+    {% block subfoot %}{% endblock %}
+{% endblock %}
diff --git a/templates/wallets/detail.html b/templates/wallets/detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..522db3c631ba954785c29d91eb798c3041b5c7cf
--- /dev/null
+++ b/templates/wallets/detail.html
@@ -0,0 +1,10 @@
+{% extends "wallets/base.html" %}
+
+{% block sub_content %}
+<h1><span class="label label-default">Wallet</span> <span class="label label-primary">{{key.uids.0|truncate(50)}}</span></h1>
+
+<div class="well">
+  {{key}}
+</div>
+
+{% endblock %}
diff --git a/templates/wallets/index.html b/templates/wallets/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..39c37577e9375c03f473e8e2d5cde59d8bb2c894
--- /dev/null
+++ b/templates/wallets/index.html
@@ -0,0 +1,19 @@
+{% extends "wallets/base.html" %}
+
+{% block sub_content %}
+<h1><span class="label label-default">Wallets</span></h1>
+
+<div class="alert alert-info">
+  Select the wallet you want to use.
+</div>
+
+<div class="list-group">
+  {% for fp,k in settings.list_keys.items() %}
+    <a href="{{ url_for('wallet_detail', pgp_fingerprint=fp) }}" class="list-group-item {% if k.keyid == settings.keyid %}active{% endif %}">
+      <h4 class="list-group-item-heading">{{k.uids.0}}</h4>
+      <p class="list-group-item-text">{{fp}}</p>
+    </a>
+  {% endfor %}
+</div>
+
+{% endblock %}
diff --git a/templates/wallets/new.html b/templates/wallets/new.html
new file mode 100644
index 0000000000000000000000000000000000000000..d59a7e9a1d72fb43f9e7995a5e5b5a1a56e85d4c
--- /dev/null
+++ b/templates/wallets/new.html
@@ -0,0 +1,115 @@
+{% extends "wallets/base.html" %}
+
+{% block sub_content %}
+<h1><span class="label label-default">Create a new wallet</span></h1>
+
+<div class="row">
+  <div class="col-md-6">
+    <div class="panel panel-info">
+      <div class="panel-heading"><h4>Type</h4></div>
+      <div class="panel-body">
+	<div class="btn-group" data-toggle="buttons">
+	  {% for key, checked in [('rsa', True), ('dsa', False)] %}
+	    <label class="btn btn-default btn-lg {% if checked %}active{% endif %}" for="type_{{key}}">
+	      <input checked="checked" id="type_{{key}}" name="type" type="radio" value="{{key}}"/> {{key|upper}}
+	    </label>
+	  {% endfor %}
+	</div>
+      </div>
+    </div>
+  </div>
+  <div class="col-md-6">
+    <div class="panel panel-info">
+      <div class="panel-heading"><h4>Length</h4></div>
+      <div class="panel-body">
+	<div class="btn-group" data-toggle="buttons">
+	  {% for length, checked in [('1024', False), ('2048', True), ('4096', False)] %}
+	    <label class="btn btn-default btn-lg {% if checked %}active{% endif %}" for="length_{{length}}">
+	      <input checked="checked" id="length_{{length}}" name="length" type="radio" value="{{length}}"/> {{length}}
+	    </label>
+	  {% endfor %}
+	</div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-info">
+  <div class="panel-heading"><h4>Email</h4></div>
+  <div class="panel-body">
+    <div class="form-group">
+      <input name="email" id="email" class="form-control input-lg"/>
+    </div>
+  </div>
+</div>
+
+<div class="panel panel-info">
+  <div class="panel-heading"><h4>Realm</h4></div>
+  <div class="panel-body">
+    <div class="form-group">
+      <input name="realm" id="realm" class="form-control input-lg"/>
+    </div>
+  </div>
+</div>
+
+<div class="alert alert-info lg"><h3 id="result">Click on "create" in order to create the new key.</h3></div>
+
+<div class="form-group">
+  <button type="button" id="create" class="btn btn-lg btn-primary btn-block" data-loading-text="Loading… It takes a moment…" data-complete-text="Finished! Create a new one." data-error-text="Fix and create" data-toggle="button">Create</button>
+</div>
+
+{% endblock %}
+
+{% block subfoot %}
+<script type=text/javascript>
+    $(function() {
+	var type = $('input[name="type"]');
+	var length = $('input[name="length"]');
+	var email = $('input[name="email"]');
+	var realm = $('input[name="realm"]');
+	var create = $('#create');
+	var result = $('#result');
+
+	var submit_form = function(e) {
+            $(this).button('loading');
+
+	    if (!(email.val())) {
+		email.parent().addClass('has-error');
+		create.button('error');
+		return false;
+	    }
+
+	    if (!(realm.val())) {
+		realm.parent().addClass('has-error');
+		create.button('error');
+		return false;
+	    }
+
+	    $.getJSON($SCRIPT_ROOT + "{{ url_for('new_wallet_create') }}", {
+		type: type.val(),
+		length: length.val(),
+		email: email.val(),
+		realm: realm.val(),
+	    }, function(data) {
+		result.parent().removeClass('alert-info');
+		result.parent().addClass('alert-success');
+		result.text(data.result);
+		email.focus().select();
+                create.button('complete');
+	    });
+
+	    return false;
+	};
+
+	create.bind('click', submit_form);
+
+	$('input[type=text]').bind('keydown', function(e) {
+	    if (e.keyCode == 13) {
+		submit_form(e);
+	    }
+	});
+
+	email.focus();
+    });
+</script>
+{% endblock %}
diff --git a/webclient.py b/webclient.py
new file mode 100755
index 0000000000000000000000000000000000000000..6c2568e7164878274db66870c923f5c8b3e8a4b4
--- /dev/null
+++ b/webclient.py
@@ -0,0 +1,395 @@
+#!/usr/bin/env python3
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Authors:
+# Caner Candan <caner@candan.fr>, http://caner.candan.fr
+#
+
+from pprint import pprint
+import ucoin, json, logging, argparse, sys, gnupg, hashlib, re, datetime as dt
+from collections import OrderedDict
+from merkle import Merkle
+from flask import Flask, request, render_template, jsonify
+from io import StringIO
+
+logger = logging.getLogger("cli")
+
+app = Flask(__name__)
+
+def render_prettyprint(template_name, result):
+    s = StringIO()
+    pprint(result, s)
+    s = s.getvalue().replace('\\r', '').replace('\\n', '\n')
+    return render_template(template_name, result=s, style='prettyprint')
+
+def format_amendment(am):
+    res = """\
+Version\t\t\t%(version)s
+Currency\t\t%(currency)s
+Number\t\t\t%(number)s
+GeneratedOn\t\t%(generated)s
+UniversalDividend\t%(dividend)s
+NextRequiredVotes\t%(nextVotes)s
+PreviousHash\t\t%(previousHash)s
+MembersRoot\t\t%(membersRoot)s
+MembersCount\t\t%(membersCount)s
+""" % am
+
+    if am['membersChanges']:
+        res += 'MembersChanges\n'
+        for x in am['membersChanges']: res += '%s\n' % x
+
+    res += """\
+VotersRoot\t\t%(votersRoot)s
+VotersCount\t\t%(votersCount)s
+""" % am
+
+    if am['votersChanges']:
+        res += 'VotersChanges\n'
+        for x in am['votersChanges']: res += '%s\n' % x
+
+    return res
+
+@app.route('/')
+@app.route('/wallets')
+def wallets():
+    return render_template('wallets/index.html', settings=ucoin.settings)
+
+@app.route('/wallets/<pgp_fingerprint>')
+def wallet_detail(pgp_fingerprint):
+    return render_template('wallets/detail.html', settings=ucoin.settings, key=ucoin.settings['list_keys'].get(pgp_fingerprint))
+
+@app.route('/wallets/new')
+def new_wallet():
+    return render_template('wallets/new.html', settings=ucoin.settings)
+
+@app.route('/wallets/new/create')
+def new_wallet_create():
+    __input = 'Key-Type: %(type)s\nName-Email: %(email)s\nName-Real: %(realm)s\nKey-Length: %(length)s\n%%commit\n' % request.args
+    newkey = ucoin.settings['gpg'].gen_key(__input)
+    return jsonify(result="Your new key (%s) has been successfully created." % newkey.fingerprint)
+
+@app.route('/api')
+def api():
+    return render_template('api/index.html')
+
+@app.route('/api/pks/add', methods=['GET', 'POST'])
+def pks_add():
+    if request.method == 'GET':
+        return render_template('api/result.html', result='POST Method has to be used')
+
+    keytext = request.form.get('keytext')
+    keysign = request.form.get('keysign')
+
+    return render_template('api/result.html', result=ucoin.pks.Add().post(keytext=keytext, keysign=keysign))
+
+@app.route('/api/pks/lookup')
+def pks_lookup():
+    search = request.args.get('search', '')
+    op = request.args.get('op', 'get')
+
+    return render_template('api/result.html', result=ucoin.pks.Lookup().get(search=search, op=op))
+
+@app.route('/api/pks/all')
+def pks_all():
+    return render_prettyprint('api/result.html', list(ucoin.pks.All().get()))
+
+@app.route('/api/ucg/pubkey')
+def ucg_pubkey():
+    return render_template('api/result.html', result=ucoin.ucg.Pubkey().get(), style='text')
+
+@app.route('/api/ucg/peering')
+def ucg_peering():
+    return render_prettyprint('api/result.html', ucoin.ucg.Peering().get())
+
+@app.route('/api/ucg/peering/keys')
+def ucg_peering_keys():
+    return render_prettyprint('api/result.html', list(ucoin.ucg.peering.Keys().get()))
+
+@app.route('/api/ucg/peering/peer')
+def ucg_peering_peer():
+    return render_prettyprint('api/result.html', ucoin.ucg.peering.Peer().get())
+
+@app.route('/api/ucg/peering/peers', methods=['GET', 'POST'])
+def ucg_peering_peers():
+    if request.method == 'GET':
+        return render_prettyprint('api/result.html', list(ucoin.ucg.peering.Peers().get()))
+
+    entry = request.form.get('entry')
+    signature = request.form.get('signature')
+
+    return render_prettyprint('api/result.html', ucoin.ucg.peering.Peers().post(entry=entry, signature=signature))
+
+@app.route('/api/ucg/peering/peers/upstream')
+def ucg_peering_peers_upstream():
+    return render_prettyprint('api/result.html', ucoin.ucg.peering.peers.UpStream().get())
+
+@app.route('/api/ucg/peering/peers/upstream/<pgp_fingerprint>')
+def ucg_peering_peers_upstream_pgp(pgp_fingerprint):
+    return render_prettyprint('api/result.html', ucoin.ucg.peering.peers.UpStream(pgp_fingerprint).get())
+
+@app.route('/api/ucg/peering/peers/downstream')
+def ucg_peering_peers_downstream():
+    return render_prettyprint('api/result.html', ucoin.ucg.peering.peers.DownStream().get())
+
+@app.route('/api/ucg/peering/peers/downstream/<pgp_fingerprint>')
+def ucg_peering_peers_downstream_pgp(pgp_fingerprint):
+    return render_prettyprint('api/result.html', ucoin.ucg.peering.peers.DownStream(pgp_fingerprint).get())
+
+@app.route('/api/ucg/peering/forward', methods=['GET', 'POST'])
+def ucg_peering_forward():
+    if request.method == 'GET':
+        return render_template('api/result.html', result='POST Method has to be used')
+
+    forward = request.form.get('forward')
+    signature = request.form.get('signature')
+
+    return render_prettyprint('api/result.html', ucoin.ucg.peering.Forward().post(forward=forward, signature=signature))
+
+@app.route('/api/ucg/peering/status', methods=['GET', 'POST'])
+def ucg_peering_status():
+    if request.method == 'GET':
+        return render_template('api/result.html', result='POST Method has to be used')
+
+    status = request.form.get('status')
+    signature = request.form.get('signature')
+
+    return render_prettyprint('api/result.html', ucoin.ucg.peering.Status().post(status=status, signature=signature))
+
+@app.route('/api/ucg/tht', methods=['GET', 'POST',])
+def ucg_tht():
+    if request.method == 'GET':
+        return render_prettyprint('api/result.html', list(ucoin.ucg.THT().get()))
+
+    entry = request.form.get('entry')
+    signature = request.form.get('signature')
+
+    return render_prettyprint('api/result.html', ucoin.ucg.THT().post(entry=entry, signature=signature))
+
+@app.route('/api/ucg/tht/<pgp_fingerprint>')
+def ucg_tht_pgp(pgp_fingerprint):
+    return render_prettyprint('api/result.html', ucoin.ucg.THT(pgp_fingerprint).get())
+
+@app.route('/api/hdc/amendments/current')
+def hdc_amendments_current():
+    return render_prettyprint('api/result.html', ucoin.hdc.amendments.Current().get())
+
+@app.route('/api/hdc/amendments/current/votes')
+def hdc_amendments_current_votes():
+    return render_prettyprint('api/result.html', list(ucoin.hdc.amendments.CurrentVotes().get()))
+
+@app.route('/api/hdc/amendments/promoted')
+def hdc_amendments_promoted():
+    return render_prettyprint('api/result.html', ucoin.hdc.amendments.Promoted().get())
+
+@app.route('/api/hdc/amendments/promoted/<int:amendment_number>')
+def hdc_amendments_promoted_am(amendment_number):
+    return render_prettyprint('api/result.html', ucoin.hdc.amendments.Promoted(amendment_number).get())
+
+@app.route('/api/hdc/amendments/view/<amendment_id>/members')
+def hdc_amendments_view_am_members(amendment_id):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.amendments.views.Members(amendment_id).get()))
+
+@app.route('/api/hdc/amendments/view/<amendment_id>/self')
+def hdc_amendments_view_am_self(amendment_id):
+    return render_prettyprint('api/result.html', ucoin.hdc.amendments.views.Self(amendment_id).get())
+
+@app.route('/api/hdc/amendments/view/<amendment_id>/voters')
+def hdc_amendments_view_am_voters(amendment_id):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.amendments.views.Voters(amendment_id).get()))
+
+@app.route('/api/hdc/amendments/view/<amendment_id>/signatures')
+def hdc_amendments_view_am_signatures(amendment_id):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.amendments.views.Signatures(amendment_id).get()))
+
+@app.route('/api/hdc/amendments/votes', methods=['GET', 'POST'])
+def hdc_amendments_votes():
+    if request.method == 'GET':
+        return render_prettyprint('api/result.html', ucoin.hdc.amendments.Votes().get())
+
+    amendment = request.form.get('amendment')
+    signature = request.form.get('signature')
+    peer = request.form.get('peer')
+
+    return render_prettyprint('api/result.html', ucoin.hdc.amendments.Votes().post(amendment=amendment, signature=signature, peer=peer))
+
+@app.route('/api/hdc/amendments/votes/<amendment_id>')
+def hdc_amendments_votes_am(amendment_id):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.amendments.Votes(amendment_id).get()))
+
+@app.route('/api/hdc/coins/<pgp_fingerprint>/list')
+def hdc_coins_pgp_list(pgp_fingerprint):
+    return render_prettyprint('api/result.html', ucoin.hdc.coins.List(pgp_fingerprint).get())
+
+@app.route('/api/hdc/coins/<pgp_fingerprint>/view/<int:coin_number>')
+def hdc_coins_pgp_view_coin(pgp_fingerprint):
+    return render_prettyprint('api/result.html', ucoin.hdc.coins.List(pgp_fingerprint, coin_number).get())
+
+@app.route('/api/hdc/coins/<pgp_fingerprint>/view/<int:coin_number>/history')
+def hdc_coins_pgp_view_coin_history(pgp_fingerprint):
+    return render_prettyprint('api/result.html', ucoin.hdc.coins.view.History(pgp_fingerprint, coin_number).get())
+
+@app.route('/api/hdc/transactions/process', methods=['POST',])
+def hdc_transactions_process():
+    transaction = request.form.get('transaction')
+    signature = request.form.get('signature')
+
+    return render_prettyprint('api/result.html', ucoin.hdc.transactions.Process().post(transaction=transaction, signature=signature))
+
+@app.route('/api/hdc/transactions/all')
+def hdc_transactions_all():
+    return render_prettyprint('api/result.html', list(ucoin.hdc.transactions.All().get()))
+
+@app.route('/api/hdc/transactions/keys')
+def hdc_transactions_keys():
+    return render_prettyprint('api/result.html', list(ucoin.hdc.transactions.Keys().get()))
+
+@app.route('/api/hdc/transactions/last')
+def hdc_transactions_last():
+    return render_prettyprint('api/result.html', ucoin.hdc.transactions.Last().get())
+
+@app.route('/api/hdc/transactions/last/<int:count>')
+def hdc_transactions_last_count(count):
+    return render_prettyprint('api/result.html', ucoin.hdc.transactions.Last(count).get())
+
+@app.route('/api/hdc/transactions/sender/<pgp_fingerprint>')
+def hdc_transactions_sender_pgp(pgp_fingerprint):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.transactions.Sender(pgp_fingerprint).get()))
+
+@app.route('/api/hdc/transactions/sender/<pgp_fingerprint>/last')
+def hdc_transactions_sender_pgp_last(pgp_fingerprint):
+    return render_prettyprint('api/result.html', ucoin.hdc.transactions.sender.Last(pgp_fingerprint).get())
+
+@app.route('/api/hdc/transactions/sender/<pgp_fingerprint>/last/<int:count>')
+def hdc_transactions_sender_pgp_last_count(pgp_fingerprint, count):
+    return render_prettyprint('api/result.html', ucoin.hdc.transactions.sender.Last(pgp_fingerprint, count).get())
+
+@app.route('/api/hdc/transactions/sender/<pgp_fingerprint>/transfer')
+def hdc_transactions_sender_pgp_transfer(pgp_fingerprint):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.transactions.sender.Transfer(pgp_fingerprint).get()))
+
+@app.route('/api/hdc/transactions/sender/<pgp_fingerprint>/issuance')
+def hdc_transactions_sender_pgp_issuance(pgp_fingerprint):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.transactions.sender.Issuance(pgp_fingerprint).get()))
+
+@app.route('/api/hdc/transactions/sender/<pgp_fingerprint>/issuance/last')
+def hdc_transactions_sender_pgp_issuance_last(pgp_fingerprint):
+    return render_prettyprint('api/result.html', ucoin.hdc.transactions.sender.issuance.Last(pgp_fingerprint).get())
+
+@app.route('/api/hdc/transactions/sender/<pgp_fingerprint>/issuance/fusion')
+def hdc_transactions_sender_pgp_issuance_fusion(pgp_fingerprint):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.transactions.sender.issuance.Fusion(pgp_fingerprint).get()))
+
+@app.route('/api/hdc/transactions/sender/<pgp_fingerprint>/issuance/dividend')
+def hdc_transactions_sender_pgp_issuance_dividend(pgp_fingerprint):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.transactions.sender.issuance.Dividend(pgp_fingerprint).get()))
+
+@app.route('/api/hdc/transactions/sender/<pgp_fingerprint>/issuance/dividend/<int:amendment_number>')
+def hdc_transactions_sender_pgp_issuance_dividend_am(pgp_fingerprint, amendment_number):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.transactions.sender.issuance.Dividend(pgp_fingerprint, amendment_number).get()))
+
+@app.route('/api/hdc/transactions/recipient/<pgp_fingerprint>')
+def hdc_transactions_recipient_pgp(pgp_fingerprint):
+    return render_prettyprint('api/result.html', list(ucoin.hdc.transactions.Recipient(pgp_fingerprint).get()))
+
+@app.route('/api/hdc/transactions/view/<transaction_id>')
+def hdc_transactions_view_tx(transaction_id):
+    return render_prettyprint('api/result.html', ucoin.hdc.transactions.View(transaction_id).get())
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description='uCoin webclient.', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+    levels = OrderedDict([('debug', logging.DEBUG),
+                          ('info', logging.INFO),
+                          ('warning', logging.WARNING),
+                          ('error', logging.ERROR),
+                          ('quiet', logging.CRITICAL),])
+
+    parser.add_argument('--verbose', '-v', choices=[x for x in levels.keys()], default='error', help='set a verbosity level')
+    parser.add_argument('--levels', '-l', action='store_true', default=False, help='list all the verbosity levels')
+    parser.add_argument('--output', '-o', help='all the logging messages are redirected to the specified filename.')
+    parser.add_argument('--debug', '-d', action='store_const', const='debug', dest='verbose', help='Display all the messages.')
+    parser.add_argument('--info', '-i', action='store_const', const='info', dest='verbose', help='Display the info messages.')
+    parser.add_argument('--warning', '-w', action='store_const', const='warning', dest='verbose', help='Only display the warning and error messages.')
+    parser.add_argument('--error', '-e', action='store_const', const='error', dest='verbose', help='Only display the error messages')
+    parser.add_argument('--quiet', '-q', action='store_const', const='quiet', dest='verbose', help='Quiet level of verbosity only displaying the critical error messages.')
+
+    parser.add_argument('--user', '-u', help='PGP key to use for signature')
+    parser.add_argument('--server', '-s', help='uCoin server to look data in', default='localhost')
+    parser.add_argument('--port', '-p', help='uCoin server port', type=int, default=8081)
+
+    parser.add_argument('--config', '-c', help='set a config file', default='config.json')
+
+    subparsers = parser.add_subparsers(help='sub-command help')
+
+    def run():
+        print('Running...')
+        app.run(debug=True)
+
+    subparsers.add_parser('run', help='Run the webclient').set_defaults(func=run)
+
+    args = parser.parse_args()
+
+    if args.levels:
+        print("Here's the verbose levels available:")
+        for keys in levels.keys():
+            print("\t", keys)
+        sys.exit()
+
+    if (args.output):
+        logging.basicConfig(
+            level=logging.DEBUG,
+            format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
+            filename=args.output, filemode='a'
+            )
+    else:
+        logging.basicConfig(
+            level=levels.get(args.verbose, logging.NOTSET),
+            format='%(name)-12s: %(levelname)-8s %(message)s'
+        )
+
+    ucoin.settings.update(args.__dict__)
+
+    try:
+        with open(args.config) as f:
+            ucoin.settings.update(json.load(f))
+    except FileNotFoundError:
+        pass
+
+    if ucoin.settings.get('user'):
+        logger.debug('selected keyid: %s' % ucoin.settings['user'])
+        ucoin.settings['gpg'] = gpg = gnupg.GPG(options=['-u %s' % ucoin.settings['user']])
+
+        keys = gpg.list_keys(True)
+        for idx, fp in enumerate(keys.fingerprints):
+            if fp[-8:] == ucoin.settings['user']:
+                ucoin.settings.update(keys[idx])
+                break
+
+        ucoin.settings['list_keys'] = __list_keys = {}
+        for k in keys: __list_keys[k['fingerprint']] = k
+    else:
+        ucoin.settings['gpg'] = gpg = gnupg.GPG()
+
+    ucoin.settings.update(ucoin.ucg.Peering().get())
+
+    logger.debug(args)
+    logger.debug(ucoin.settings)
+
+    if 'func' not in args:
+        parser.print_help()
+        sys.exit()
+
+    args.func()